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