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