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