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