Rank-weight may be controlled via query.
[idzebra-moved-to-github.git] / index / rank1.c
1 /*
2  * Copyright (C) 1998-1999, Index Data
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: rank1.c,v $
7  * Revision 1.7  2001-11-14 22:06:27  adam
8  * Rank-weight may be controlled via query.
9  *
10  * Revision 1.6  2000/03/15 15:00:30  adam
11  * First work on threaded version.
12  *
13  * Revision 1.5  1999/05/26 07:49:13  adam
14  * C++ compilation.
15  *
16  * Revision 1.4  1999/02/02 14:51:01  adam
17  * Updated WIN32 code specific sections. Changed header.
18  *
19  * Revision 1.3  1998/06/12 12:21:53  adam
20  * Fixed memory-leak.
21  *
22  * Revision 1.2  1998/03/05 13:03:29  adam
23  * Improved ranking.
24  *
25  * Revision 1.1  1998/03/05 08:45:12  adam
26  * New result set model and modular ranking system. Moved towards
27  * descent server API. System information stored as "SGML" records.
28  *
29  */
30
31 #include <stdio.h>
32 #include <assert.h>
33 #ifdef WIN32
34 #include <io.h>
35 #else
36 #include <unistd.h>
37 #endif
38
39 #include "zserver.h"
40
41 struct rank_class_info {
42     int dummy;
43 };
44
45 struct rank_term_info {
46     int local_occur;
47     int global_occur;
48     int global_inv;
49     int rank_flag;
50     int rank_weight;
51 };
52
53 struct rank_set_info {
54     int last_pos;
55     int no_entries;
56     int no_rank_entries;
57     struct rank_term_info *entries;
58 };
59
60 static int log2_int (unsigned g)
61 {
62     int n = 0;
63     while ((g = g>>1))
64         n++;
65     return n;
66 }
67
68 /*
69  * create: Creates/Initialises this rank handler. This routine is 
70  *  called exactly once. The routine returns the class_handle.
71  */
72 static void *create (ZebraService zh)
73 {
74     struct rank_class_info *ci = (struct rank_class_info *)
75         xmalloc (sizeof(*ci));
76
77     logf (LOG_DEBUG, "rank-1 create");
78     return ci;
79 }
80
81 /*
82  * destroy: Destroys this rank handler. This routine is called
83  *  when the handler is no longer needed - i.e. when the server
84  *  dies. The class_handle was previously returned by create.
85  */
86 static void destroy (ZebraService zh, void *class_handle)
87 {
88     struct rank_class_info *ci = (struct rank_class_info *) class_handle;
89
90     logf (LOG_DEBUG, "rank-1 destroy");
91     xfree (ci);
92 }
93
94
95 /*
96  * begin: Prepares beginning of "real" ranking. Called once for
97  *  each result set. The returned handle is a "set handle" and
98  *  will be used in each of the handlers below.
99  */
100 static void *begin (ZebraHandle zh, void *class_handle, RSET rset)
101 {
102     struct rank_set_info *si = (struct rank_set_info *) xmalloc (sizeof(*si));
103     int i;
104
105     logf (LOG_DEBUG, "rank-1 begin");
106     si->no_entries = rset->no_rset_terms;
107     si->no_rank_entries = 0;
108     si->entries = (struct rank_term_info *)
109         xmalloc (sizeof(*si->entries)*si->no_entries);
110     for (i = 0; i < si->no_entries; i++)
111     {
112         int g = rset->rset_terms[i]->nn;
113         if (!strncmp (rset->rset_terms[i]->flags, "rank,", 5))
114         {
115             yaz_log (LOG_LOG, "%s", rset->rset_terms[i]->flags);
116             si->entries[i].rank_flag = 1;
117             si->entries[i].rank_weight = atoi (rset->rset_terms[i]->flags+5);
118             yaz_log (LOG_LOG, "i=%d weight=%d", i, si->entries[i].rank_weight);
119             (si->no_rank_entries)++;
120         }
121         else
122             si->entries[i].rank_flag = 0;
123         si->entries[i].local_occur = 0;
124         si->entries[i].global_occur = g;
125         si->entries[i].global_inv = 32 - log2_int (g);
126         logf (LOG_DEBUG, "-------- %d ------", 32 - log2_int (g));
127     }
128     return si;
129 }
130
131 /*
132  * end: Terminates ranking process. Called after a result set
133  *  has been ranked.
134  */
135 static void end (ZebraHandle zh, void *set_handle)
136 {
137     struct rank_set_info *si = (struct rank_set_info *) set_handle;
138     logf (LOG_DEBUG, "rank-1 end");
139     xfree (si->entries);
140     xfree (si);
141 }
142
143 /*
144  * add: Called for each word occurence in a result set. This routine
145  *  should be as fast as possible. This routine should "incrementally"
146  *  update the score.
147  */
148 static void add (void *set_handle, int seqno, int term_index)
149 {
150     struct rank_set_info *si = (struct rank_set_info *) set_handle;
151     logf (LOG_DEBUG, "rank-1 add seqno=%d term_index=%d", seqno, term_index);
152     si->last_pos = seqno;
153     si->entries[term_index].local_occur++;
154 }
155
156 /*
157  * calc: Called for each document in a result. This handler should 
158  *  produce a score based on previous call(s) to the add handler. The
159  *  score should be between 0 and 1000. If score cannot be obtained
160  *  -1 should be returned.
161  */
162 static int calc (void *set_handle, int sysno)
163 {
164     int i, lo, divisor, score = 0;
165     struct rank_set_info *si = (struct rank_set_info *) set_handle;
166
167     logf (LOG_DEBUG, "rank-1 calc sysno=%d", sysno);
168
169     if (!si->no_rank_entries)
170         return -1;
171     for (i = 0; i < si->no_entries; i++)
172         if (si->entries[i].rank_flag && (lo = si->entries[i].local_occur))
173             score += (8+log2_int (lo)) * si->entries[i].global_inv *
174                 si->entries[i].rank_weight;
175     divisor = si->no_rank_entries * (8+log2_int (si->last_pos/si->no_entries));
176     score = score / divisor;
177     yaz_log (LOG_LOG, "score=%d", score);
178     if (score > 1000)
179         score = 1000;
180     for (i = 0; i < si->no_entries; i++)
181         si->entries[i].local_occur = 0;
182     return score;
183 }
184
185 /*
186  * Pseudo-meta code with sequence of calls as they occur in a
187  * server. Handlers are prefixed by --:
188  *
189  *     server init
190  *     -- create
191  *     foreach search
192  *        rank result set
193  *        -- begin
194  *        foreach record
195  *           foreach word
196  *              -- add
197  *           -- calc
198  *        -- end
199  *     -- destroy
200  *     server close
201  */
202
203 static struct rank_control rank_control = {
204     "rank-1",
205     create,
206     destroy,
207     begin,
208     end,
209     calc,
210     add,
211 };
212  
213 struct rank_control *rank1_class = &rank_control;