Bug fix: result sets with ranked operands in boolean operations weren't
[idzebra-moved-to-github.git] / rset / rsrel.c
1 /*
2  * Copyright (C) 1994-1995, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: rsrel.c,v $
7  * Revision 1.12  1996-10-08 13:00:40  adam
8  * Bug fix: result sets with ranked operands in boolean operations weren't
9  * sorted.
10  *
11  * Revision 1.11  1996/10/07  16:05:29  quinn
12  * Work.
13  *
14  * Revision 1.9  1995/12/11  09:15:26  adam
15  * New set types: sand/sor/snot - ranked versions of and/or/not in
16  * ranked/semi-ranked result sets.
17  * Note: the snot not finished yet.
18  * New rset member: flag.
19  * Bug fix: r_delete in rsrel.c did free bad memory block.
20  *
21  * Revision 1.8  1995/12/05  11:25:45  adam
22  * Doesn't include math.h.
23  *
24  * Revision 1.7  1995/10/12  12:41:57  adam
25  * Private info (buf) moved from struct rset_control to struct rset.
26  * Bug fixes in relevance.
27  *
28  * Revision 1.6  1995/10/10  14:00:04  adam
29  * Function rset_open changed its wflag parameter to general flags.
30  *
31  * Revision 1.5  1995/10/06  14:38:06  adam
32  * New result set method: r_score.
33  * Local no (sysno) and score is transferred to retrieveCtrl.
34  *
35  * Revision 1.4  1995/09/14  07:48:56  adam
36  * Other score calculation.
37  *
38  * Revision 1.3  1995/09/11  15:23:40  adam
39  * More work on relevance search.
40  *
41  * Revision 1.2  1995/09/11  13:09:41  adam
42  * More work on relevance feedback.
43  *
44  * Revision 1.1  1995/09/08  14:52:42  adam
45  * Work on relevance feedback.
46  *
47  */
48
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <assert.h>
52
53 #include <isam.h>
54 #include <rsrel.h>
55 #include <alexutil.h>
56
57 static void *r_create(const struct rset_control *sel, void *parms,
58                       int *flags);
59 static RSFD r_open (RSET ct, int flag);
60 static void r_close (RSFD rfd);
61 static void r_delete (RSET ct);
62 static void r_rewind (RSFD rfd);
63 static int r_count (RSET ct);
64 static int r_read (RSFD rfd, void *buf);
65 static int r_write (RSFD rfd, const void *buf);
66 static int r_score (RSFD rfd, int *score);
67
68 static const rset_control control = 
69 {
70     "relevance",
71     r_create,
72     r_open,
73     r_close,
74     r_delete,
75     r_rewind,
76     r_count,
77     r_read,
78     r_write,
79     r_score
80 };
81
82 const rset_control *rset_kind_relevance = &control;
83
84 struct rset_rel_info {
85     int     key_size;
86     int     max_rec;
87     int     no_rec;
88     int     (*cmp)(const void *p1, const void *p2);
89     char    *key_buf;                   /* key buffer */
90     float   *score_buf;                 /* score buffer */
91     int     *sort_idx;                  /* score sorted index */
92     int     *sysno_idx;                /* sysno sorted index (ring buffer) */
93     struct rset_rel_rfd *rfd_list;
94 };
95
96 struct rset_rel_rfd {
97     int     last_read_pos;
98     int     position;
99     int     flag;
100     struct rset_rel_rfd *next;
101     struct rset_rel_info *info;
102 };
103
104 static void add_rec (struct rset_rel_info *info, double score, void *key)
105 {
106     int idx, i, j;
107
108     for (i = 0; i<info->no_rec; i++)
109     {
110         idx = info->sort_idx[i];
111         if (score <= info->score_buf[idx])
112             break;
113     }
114     if (info->no_rec < info->max_rec)
115     {                                        /* there is room for this entry */
116         for (j = info->no_rec; j > i; --j)
117             info->sort_idx[j] = info->sort_idx[j-1];
118         idx = info->sort_idx[j] = info->no_rec;
119         ++(info->no_rec);
120     }
121     else if (i == 0)
122         return;                              /* score too low */
123     else
124     {
125         idx = info->sort_idx[0];             /* remove this entry */
126
127         --i;
128         for (j = 0; j < i; ++j)              /* make room */
129             info->sort_idx[j] = info->sort_idx[j+1];
130         info->sort_idx[j] = idx;             /* allocate sort entry */
131     }
132     memcpy (info->key_buf + idx*info->key_size, key, info->key_size);
133     info->score_buf[idx] = score;
134 }
135
136
137 static struct rset_rel_info *qsort_info;
138
139 static int qcomp (const void *p1, const void *p2)
140 {
141     int i1 = *(int*) p1;
142     int i2 = *(int*) p2;
143
144     return qsort_info->cmp (qsort_info->key_buf + i1*qsort_info->key_size,
145                             qsort_info->key_buf + i2*qsort_info->key_size);
146 }
147
148 #define SCORE_SHOW 0.0                       /* base score for showing up */
149 #define SCORE_COOC 0.3                       /* component dependent on co-oc */
150 #define SCORE_DYN  (1-(SCORE_SHOW+SCORE_COOC)) /* dynamic component of score */
151
152 static void relevance (struct rset_rel_info *info, rset_relevance_parms *parms)
153 {
154     char **isam_buf;
155     char *isam_tmp_buf;
156     int  *isam_r;
157     int  *max_tf, *tf;
158     ISPT *isam_pt;
159     int i;
160
161     logf (LOG_DEBUG, "relevance");
162     isam_buf = xmalloc (parms->no_isam_positions * sizeof(*isam_buf));
163     isam_r = xmalloc (sizeof (*isam_r) * parms->no_isam_positions);
164     isam_pt = xmalloc (sizeof (*isam_pt) * parms->no_isam_positions);
165     isam_tmp_buf = xmalloc (info->key_size);
166     max_tf = xmalloc (sizeof (*max_tf) * parms->no_terms);
167     tf = xmalloc (sizeof (*tf) * parms->no_terms);
168
169     for (i = 0; i<parms->no_terms; i++)
170         max_tf[i] = 0;
171     for (i = 0; i<parms->no_isam_positions; i++)
172     {
173         isam_buf[i] = xmalloc (info->key_size);
174         isam_pt[i] = is_position (parms->is, parms->isam_positions[i]);
175         max_tf [parms->term_no[i]] = is_numkeys (isam_pt[i]);
176         isam_r[i] = is_readkey (isam_pt[i], isam_buf[i]);
177         logf (LOG_DEBUG, "max tf %d = %d", i, max_tf[i]);
178     }
179     while (1)
180     {
181         int min = -1, i, r;
182         double score;
183         int co_oc, last_term;    /* Number of co-occurrences */
184
185         last_term = -1;
186         /* find min with lowest sysno */
187         for (i = 0; i<parms->no_isam_positions; i++)
188         {
189             if (isam_r[i] && 
190                (min < 0 || (r = (*parms->cmp)(isam_buf[i], isam_buf[min])) < 2))
191             {
192                 min = i;
193                 co_oc = 1;
194             }
195             else if (!r && last_term != parms->term_no[i]) /* new occurrence */
196                 co_oc++;
197             last_term = parms->term_no[i];
198         }
199         
200         if (min < 0)
201             break;
202         memcpy (isam_tmp_buf, isam_buf[min], info->key_size);
203         /* calculate for all with those sysno */
204         for (i = 0; i < parms->no_terms; i++)
205             tf[i] = 0;
206         for (i = 0; i<parms->no_isam_positions; i++)
207         {
208             int r;
209             
210             if (isam_r[i])
211                 r = (*parms->cmp)(isam_buf[i], isam_tmp_buf);
212             else 
213                 r = 2;
214             if (r <= 1 && r >= -1)
215             {
216                 do
217                 {
218                     tf[parms->term_no[i]]++;
219                     isam_r[i] = is_readkey (isam_pt[i], isam_buf[i]);
220                 } while (isam_r[i] && 
221                          (*parms->cmp)(isam_buf[i], isam_tmp_buf) <= 1);
222             }
223         }
224         /* calculate relevance value */
225         score = 0.0;
226         for (i = 0; i<parms->no_terms; i++)
227             if (tf[i])
228                 score += SCORE_SHOW + SCORE_COOC*co_oc/parms->no_terms +
229                     SCORE_DYN*tf[i]/max_tf[i];
230         /* if value is in the top score, then save it - don't emit yet */
231         add_rec (info, score/parms->no_terms, isam_tmp_buf);
232     }
233     for (i = 0; i<info->no_rec; i++)
234         info->sysno_idx[i] = i;
235     qsort_info = info;
236     qsort (info->sysno_idx, info->no_rec, sizeof(*info->sysno_idx), qcomp);
237     for (i = 0; i<parms->no_isam_positions; i++)
238     {
239         is_pt_free (isam_pt[i]);
240         xfree (isam_buf[i]);
241     }
242     xfree (max_tf);
243     xfree (isam_tmp_buf);
244     xfree (isam_buf);
245     xfree (isam_r);
246     xfree (isam_pt);
247     xfree(tf);
248 }
249
250 static void *r_create (const struct rset_control *sel, void *parms,
251                        int *flags)
252 {
253     rset_relevance_parms *r_parms = parms;
254     struct rset_rel_info *info;
255
256     *flags |= RSET_FLAG_RANKED;
257     info = xmalloc (sizeof(struct rset_rel_info));
258     info->key_size = r_parms->key_size;
259     assert (info->key_size > 1);
260     info->max_rec = r_parms->max_rec;
261     assert (info->max_rec > 1);
262     info->cmp = r_parms->cmp;
263
264     info->key_buf = xmalloc (info->key_size * info->max_rec);
265     info->score_buf = xmalloc (sizeof(*info->score_buf) * info->max_rec);
266     info->sort_idx = xmalloc (sizeof(*info->sort_idx) * info->max_rec);
267     info->sysno_idx = xmalloc (sizeof(*info->sysno_idx) * info->max_rec);
268     info->no_rec = 0;
269     info->rfd_list = NULL;
270
271     relevance (info, r_parms);
272     return info;
273 }
274
275 static RSFD r_open (RSET ct, int flag)
276 {
277     struct rset_rel_rfd *rfd;
278     struct rset_rel_info *info = ct->buf;
279
280     if (flag & RSETF_WRITE)
281     {
282         logf (LOG_FATAL, "relevance set type is read-only");
283         return NULL;
284     }
285     rfd = xmalloc (sizeof(*rfd));
286     rfd->flag = flag;
287     rfd->next = info->rfd_list;
288     rfd->info = info;
289     info->rfd_list = rfd;
290     r_rewind (rfd);
291     return rfd;
292 }
293
294 static void r_close (RSFD rfd)
295 {
296     struct rset_rel_info *info = ((struct rset_rel_rfd*)rfd)->info;
297     struct rset_rel_rfd **rfdp;
298     
299     for (rfdp = &info->rfd_list; *rfdp; rfdp = &(*rfdp)->next)
300         if (*rfdp == rfd)
301         {
302             *rfdp = (*rfdp)->next;
303             free (rfd);
304             return;
305         }
306     logf (LOG_FATAL, "r_close but no rfd match!");
307     assert (0);
308 }
309
310 static void r_delete (RSET ct)
311 {
312     struct rset_rel_info *info = ct->buf;
313
314     assert (info->rfd_list == NULL);
315     xfree (info->key_buf);
316     xfree (info->score_buf);
317     xfree (info->sort_idx);
318     xfree (info->sysno_idx);
319     xfree (info);
320 }
321
322 static void r_rewind (RSFD rfd)
323 {
324     struct rset_rel_rfd *p = rfd;
325     struct rset_rel_info *info = p->info;
326
327     if (p->flag & RSETF_SORT_RANK)
328         p->position = info->no_rec;
329     else
330         p->position = 0;
331 }
332
333 static int r_count (RSET ct)
334 {
335     struct rset_rel_info *info = ct->buf;
336
337     return info->no_rec;
338 }
339
340 static int r_read (RSFD rfd, void *buf)
341 {
342     struct rset_rel_rfd *p = rfd;
343     struct rset_rel_info *info = p->info;
344
345     if (p->flag & RSETF_SORT_RANK)
346     {
347         if (p->position <= 0)
348             return 0;
349         --(p->position);
350         p->last_read_pos = info->sort_idx[p->position];
351     }
352     else
353     {
354         if (p->position == info->no_rec)
355             return 0;
356         p->last_read_pos = info->sysno_idx[p->position];
357         ++(p->position);
358     }
359     memcpy ((char*) buf,
360             info->key_buf + info->key_size * p->last_read_pos,
361             info->key_size);
362     return 1;
363 }
364
365 static int r_score (RSFD rfd, int *score)
366 {
367     struct rset_rel_rfd *p = rfd;
368     struct rset_rel_info *info = p->info;
369
370     *score = (int) (1000*info->score_buf[p->last_read_pos]);
371     return 1;
372 }
373
374 static int r_write (RSFD rfd, const void *buf)
375 {
376     logf (LOG_FATAL, "relevance set type is read-only");
377     return -1;
378 }