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