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