Added feature to specify sort criteria in query (type 7 specifies
[idzebra-moved-to-github.git] / index / zsets.c
1 /*
2  * Copyright (C) 1994-1998, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: zsets.c,v $
7  * Revision 1.17  1998-06-23 15:33:36  adam
8  * Added feature to specify sort criteria in query (type 7 specifies
9  * sort flags).
10  *
11  * Revision 1.16  1998/05/20 10:12:24  adam
12  * Implemented automatic EXPLAIN database maintenance.
13  * Modified Zebra to work with ASN.1 compiled version of YAZ.
14  *
15  * Revision 1.15  1998/03/05 08:45:14  adam
16  * New result set model and modular ranking system. Moved towards
17  * descent server API. System information stored as "SGML" records.
18  *
19  * Revision 1.14  1998/02/10 16:39:15  adam
20  * Minor change.
21  *
22  * Revision 1.13  1998/02/10 12:03:06  adam
23  * Implemented Sort.
24  *
25  * Revision 1.12  1997/09/25 14:57:36  adam
26  * Windows NT port.
27  *
28  * Revision 1.11  1996/12/23 15:30:46  adam
29  * Work on truncation.
30  * Bug fix: result sets weren't deleted after server shut down.
31  *
32  * Revision 1.10  1995/10/30 15:08:08  adam
33  * Bug fixes.
34  *
35  * Revision 1.9  1995/10/17  18:02:14  adam
36  * New feature: databases. Implemented as prefix to words in dictionary.
37  *
38  * Revision 1.8  1995/10/10  13:59:25  adam
39  * Function rset_open changed its wflag parameter to general flags.
40  *
41  * Revision 1.7  1995/10/06  14:38:01  adam
42  * New result set method: r_score.
43  * Local no (sysno) and score is transferred to retrieveCtrl.
44  *
45  * Revision 1.6  1995/09/28  09:19:49  adam
46  * xfree/xmalloc used everywhere.
47  * Extract/retrieve method seems to work for text records.
48  *
49  * Revision 1.5  1995/09/27  16:17:32  adam
50  * More work on retrieve.
51  *
52  * Revision 1.4  1995/09/07  13:58:36  adam
53  * New parameter: result-set file descriptor (RSFD) to support multiple
54  * positions within the same result-set.
55  * Boolean operators: and, or, not implemented.
56  * Result-set references.
57  *
58  * Revision 1.3  1995/09/06  16:11:19  adam
59  * Option: only one word key per file.
60  *
61  * Revision 1.2  1995/09/06  10:33:04  adam
62  * More work on present. Some log messages removed.
63  *
64  * Revision 1.1  1995/09/05  15:28:40  adam
65  * More work on search engine.
66  *
67  */
68 #include <stdio.h>
69 #include <assert.h>
70 #ifdef WINDOWS
71 #include <io.h>
72 #else
73 #include <unistd.h>
74 #endif
75
76 #include "zserver.h"
77 #include <rstemp.h>
78
79 #define SORT_IDX_ENTRYSIZE 64
80 #define ZSET_SORT_MAX_LEVEL 3
81
82 struct zebra_set {
83     char *name;
84     RSET rset;
85     int size;
86     struct zset_sort_info *sort_info;
87     struct zebra_set *next;
88 };
89
90 struct zset_sort_entry {
91     int sysno;
92     int score;
93     char buf[ZSET_SORT_MAX_LEVEL][SORT_IDX_ENTRYSIZE];
94 };
95
96 struct zset_sort_info {
97     int max_entries;
98     int num_entries;
99     struct zset_sort_entry *all_entries;
100     struct zset_sort_entry **entries;
101 };
102
103 void resultSetRank (ZebraHandle zh, struct zset_sort_info *si,
104                     RSET rset, int *hits);
105
106 ZebraSet resultSetAdd (ZebraHandle zh, const char *name, int ov,
107                           RSET rset, int *hits)
108 {
109     ZebraSet s;
110     int i;
111
112     for (s = zh->sets; s; s = s->next)
113         if (!strcmp (s->name, name))
114         {
115             logf (LOG_DEBUG, "updating result set %s", name);
116             if (!ov)
117                 return NULL;
118             rset_delete (s->rset);
119             s->rset = rset;
120             resultSetRank (zh, s->sort_info, rset, hits);
121             return s;
122         }
123     logf (LOG_DEBUG, "adding result set %s", name);
124     s = xmalloc (sizeof(*s));
125     s->next = zh->sets;
126     zh->sets = s;
127     s->name = xmalloc (strlen(name)+1);
128     strcpy (s->name, name);
129     s->rset = rset;
130     
131     s->sort_info = xmalloc (sizeof(*s->sort_info));
132     s->sort_info->max_entries = 1000;
133     s->sort_info->entries = xmalloc (sizeof(*s->sort_info->entries) *
134                                      s->sort_info->max_entries);
135     s->sort_info->all_entries = xmalloc (sizeof(*s->sort_info->all_entries) *
136                                          s->sort_info->max_entries);
137     for (i = 0; i < s->sort_info->max_entries; i++)
138         s->sort_info->entries[i] = s->sort_info->all_entries + i;
139     resultSetRank (zh, s->sort_info, rset, hits);
140     return s;
141 }
142
143 ZebraSet resultSetGet (ZebraHandle zh, const char *name)
144 {
145     ZebraSet s;
146
147     for (s = zh->sets; s; s = s->next)
148         if (!strcmp (s->name, name))
149             return s;
150     return NULL;
151 }
152
153     
154 void resultSetDestroy (ZebraHandle zh)
155 {
156     ZebraSet s, s1;
157
158     for (s = zh->sets; s; s = s1)
159     {
160         s1 = s->next;
161
162         xfree (s->sort_info->all_entries);
163         xfree (s->sort_info->entries);
164         xfree (s->sort_info);
165
166         rset_delete (s->rset);
167         xfree (s->name);
168         xfree (s);
169     }
170     zh->sets = NULL;
171 }
172
173 ZebraPosSet zebraPosSetCreate (ZebraHandle zh, const char *name, 
174                                int num, int *positions)
175 {
176     ZebraSet sset;
177     ZebraPosSet sr;
178     RSET rset;
179     int i;
180     struct zset_sort_info *sort_info;
181
182     if (!(sset = resultSetGet (zh, name)))
183         return NULL;
184     if (!(rset = sset->rset))
185         return NULL;
186     sr = xmalloc (sizeof(*sr) * num);
187     for (i = 0; i<num; i++)
188     {
189         sr[i].sysno = 0;
190         sr[i].score = -1;
191     }
192     sort_info = sset->sort_info;
193     if (sort_info)
194     {
195         int position;
196
197         for (i = 0; i<num; i++)
198         {
199             position = positions[i];
200             if (position <= sort_info->num_entries)
201             {
202                 logf (LOG_DEBUG, "got pos=%d (sorted)", position);
203                 sr[i].sysno = sort_info->entries[position-1]->sysno;
204                 sr[i].score = sort_info->entries[position-1]->score;
205             }
206         }
207     }
208     /* did we really get all entries using sort ? */
209     for (i = 0; i<num; i++)
210     {
211         if (!sr[i].sysno)
212             break;
213     }
214     if (i < num) /* nope, get the rest, unsorted - sorry */
215     {
216         int position = 0;
217         int num_i = 0;
218         int psysno = 0;
219         int term_index;
220         RSFD rfd;
221         struct it_key key;
222
223         if (sort_info)
224             position = sort_info->num_entries;
225         while (num_i < num && positions[num_i] < position)
226             num_i++;
227         rfd = rset_open (rset, RSETF_READ);
228         while (num_i < num && rset_read (rset, rfd, &key, &term_index))
229         {
230             if (key.sysno != psysno)
231             {
232                 psysno = key.sysno;
233                 if (sort_info)
234                 {
235                     /* determine we alreay have this in our set */
236                     for (i = sort_info->num_entries; --i >= 0; )
237                         if (psysno == sort_info->entries[i]->sysno)
238                             break;
239                     if (i >= 0)
240                         continue;
241                 }
242                 position++;
243                 assert (num_i < num);
244                 if (position == positions[num_i])
245                 {
246                     sr[num_i].sysno = psysno;
247                     logf (LOG_DEBUG, "got pos=%d (unsorted)", position);
248                     sr[num_i].score = -1;
249                     num_i++;
250                 }
251             }
252         }
253         rset_close (rset, rfd);
254     }
255     return sr;
256 }
257
258 void zebraPosSetDestroy (ZebraHandle zh, ZebraPosSet records, int num)
259 {
260     xfree (records);
261 }
262
263 struct sortKey {
264     int relation;
265     int attrUse;
266 };
267
268 void resultSetInsertSort (ZebraHandle zh, ZebraSet sset,
269                           struct sortKey *criteria, int num_criteria,
270                           int sysno)
271 {
272     struct zset_sort_entry this_entry;
273     struct zset_sort_entry *new_entry = NULL;
274     struct zset_sort_info *sort_info = sset->sort_info;
275     int i, j;
276
277     sortIdx_sysno (zh->sortIdx, sysno);
278     for (i = 0; i<num_criteria; i++)
279     {
280         sortIdx_type (zh->sortIdx, criteria[i].attrUse);
281         sortIdx_read (zh->sortIdx, this_entry.buf[i]);
282     }
283     i = sort_info->num_entries;
284     while (--i >= 0)
285     {
286         int rel = 0;
287         for (j = 0; j<num_criteria; j++)
288         {
289             rel = memcmp (this_entry.buf[j], sort_info->entries[i]->buf[j],
290                           SORT_IDX_ENTRYSIZE);
291             if (rel)
292                 break;
293         }       
294         if (!rel)
295             break;
296         if (criteria[j].relation == 'A')
297         {
298             if (rel > 0)
299                 break;
300         }
301         else if (criteria[j].relation == 'D')
302         {
303             if (rel < 0)
304                 break;
305         }
306     }
307     j = sort_info->max_entries-1;
308     if (i == j)
309         return;
310     ++i;
311     new_entry = sort_info->entries[j];
312     while (j != i)
313     {
314         sort_info->entries[j] = sort_info->entries[j-1];
315         --j;
316     }
317     sort_info->entries[j] = new_entry;
318     assert (new_entry);
319     if (sort_info->num_entries != sort_info->max_entries)
320         (sort_info->num_entries)++;
321     for (i = 0; i<num_criteria; i++)
322         memcpy (new_entry->buf[i], this_entry.buf[i], SORT_IDX_ENTRYSIZE);
323     new_entry->sysno = sysno;
324     new_entry->score = -1;
325 }
326
327 void resultSetInsertRank (ZebraHandle zh, struct zset_sort_info *sort_info,
328                           int sysno, int score, int relation)
329 {
330     struct zset_sort_entry *new_entry = NULL;
331     int i, j;
332
333     i = sort_info->num_entries;
334     while (--i >= 0)
335     {
336         int rel = 0;
337
338         rel = score - sort_info->entries[i]->score;
339
340         if (relation == 'D')
341         {
342             if (rel >= 0)
343                 break;
344         }
345         else if (relation == 'A')
346         {
347             if (rel <= 0)
348                 break;
349         }
350     }
351     j = sort_info->max_entries-1;
352     if (i == j)
353         return;
354     ++i;
355     new_entry = sort_info->entries[j];
356     while (j != i)
357     {
358         sort_info->entries[j] = sort_info->entries[j-1];
359         --j;
360     }
361     sort_info->entries[j] = new_entry;
362     assert (new_entry);
363     if (sort_info->num_entries != sort_info->max_entries)
364         (sort_info->num_entries)++;
365     new_entry->sysno = sysno;
366     new_entry->score = score;
367 }
368
369 void resultSetSort (ZebraHandle zh, ODR stream,
370                     int num_input_setnames, const char **input_setnames,
371                     const char *output_setname,
372                     Z_SortKeySpecList *sort_sequence, int *sort_status)
373 {
374     ZebraSet sset;
375     RSET rset;
376     int i, psysno = 0;
377     struct it_key key;
378     struct sortKey sort_criteria[3];
379     int num_criteria;
380     int term_index;
381     RSFD rfd;
382
383     if (num_input_setnames == 0)
384     {
385         zh->errCode = 208;
386         return ;
387     }
388     if (num_input_setnames > 1)
389     {
390         zh->errCode = 230;
391         return;
392     }
393     logf (LOG_DEBUG, "result set sort input=%s output=%s",
394           *input_setnames, output_setname);
395     sset = resultSetGet (zh, input_setnames[0]);
396     if (!sset)
397     {
398         zh->errCode = 30;
399         zh->errString = nmem_strdup (stream->mem, input_setnames[0]);
400         return;
401     }
402     if (!(rset = sset->rset))
403     {
404         zh->errCode = 30;
405         zh->errString = nmem_strdup (stream->mem, input_setnames[0]);
406         return;
407     }
408     num_criteria = sort_sequence->num_specs;
409     if (num_criteria > 3)
410         num_criteria = 3;
411     for (i = 0; i < num_criteria; i++)
412     {
413         Z_SortKeySpec *sks = sort_sequence->specs[i];
414         Z_SortKey *sk;
415
416         if (*sks->sortRelation == Z_SortRelation_ascending)
417             sort_criteria[i].relation = 'A';
418         else if (*sks->sortRelation == Z_SortRelation_descending)
419             sort_criteria[i].relation = 'D';
420         else
421         {
422             zh->errCode = 214;
423             return;
424         }
425         if (sks->sortElement->which == Z_SortElement_databaseSpecific)
426         {
427             zh->errCode = 210;
428             return;
429         }
430         else if (sks->sortElement->which != Z_SortElement_generic)
431         {
432             zh->errCode = 237;
433             return;
434         }       
435         sk = sks->sortElement->u.generic;
436         switch (sk->which)
437         {
438         case Z_SortKey_sortField:
439             logf (LOG_DEBUG, "Sort: key %d is of type sortField", i+1);
440             zh->errCode = 207;
441             return;
442         case Z_SortKey_elementSpec:
443             logf (LOG_DEBUG, "Sort: key %d is of type elementSpec", i+1);
444             zh->errCode = 207;
445             return;
446         case Z_SortKey_sortAttributes:
447             logf (LOG_DEBUG, "Sort: key %d is of type sortAttributes", i+1);
448             sort_criteria[i].attrUse =
449                 zebra_maps_sort (zh->zebra_maps, sk->u.sortAttributes);
450             logf (LOG_DEBUG, "use value = %d", sort_criteria[i].attrUse);
451             if (sort_criteria[i].attrUse == -1)
452             {
453                 zh->errCode = 116;
454                 return;
455             }
456             if (sortIdx_type (zh->sortIdx, sort_criteria[i].attrUse))
457             {
458                 zh->errCode = 207;
459                 return;
460             }
461             break;
462         }
463     }
464     if (strcmp (output_setname, input_setnames[0]))
465     {
466         int hits;
467         rset = rset_dup (rset);
468         sset = resultSetAdd (zh, output_setname, 1, rset, &hits);
469     }
470     sset->sort_info->num_entries = 0;
471
472     rfd = rset_open (rset, RSETF_READ);
473     while (rset_read (rset, rfd, &key, &term_index))
474     {
475         if (key.sysno != psysno)
476         {
477             psysno = key.sysno;
478             resultSetInsertSort (zh, sset,
479                                  sort_criteria, num_criteria, psysno);
480         }
481     }
482     rset_close (rset, rfd);
483
484     zh->errCode = 0;
485     *sort_status = Z_SortStatus_success;
486     
487     return;
488 }
489
490 RSET resultSetRef (ZebraHandle zh, Z_ResultSetId *resultSetId)
491 {
492     ZebraSet s;
493
494     if ((s = resultSetGet (zh, resultSetId)))
495         return s->rset;
496     return NULL;
497 }
498
499 void resultSetRank (ZebraHandle zh, struct zset_sort_info *sort_info,
500                     RSET rset, int *hits)
501 {
502     int kno = 0;
503     struct it_key key;
504     RSFD rfd;
505     int term_index, i;
506     ZebraRankClass rank_class;
507     struct rank_control *rc;
508
509     sort_info->num_entries = 0;
510     *hits = 0;
511     rfd = rset_open (rset, RSETF_READ);
512
513     logf (LOG_DEBUG, "resultSetRank");
514     for (i = 0; i < rset->no_rset_terms; i++)
515         logf (LOG_DEBUG, "term=\"%s\" cnt=%d type=%s",
516               rset->rset_terms[i]->name,
517               rset->rset_terms[i]->nn,
518               rset->rset_terms[i]->flags);
519
520     rank_class = zebraRankLookup (zh, "rank-1");
521     rc = rank_class->control;
522
523     if (rset_read (rset, rfd, &key, &term_index))
524     {
525         int psysno = key.sysno;
526         int score;
527         void *handle =
528             (*rc->begin) (zh, rank_class->class_handle, rset);
529         (*hits)++;
530         do
531         {
532             kno++;
533             if (key.sysno != psysno)
534             {
535                 score = (*rc->calc) (handle, psysno);
536
537                 resultSetInsertRank (zh, sort_info, psysno, score, 'A');
538                 (*hits)++;
539                 psysno = key.sysno;
540             }
541             (*rc->add) (handle, key.seqno, term_index);
542         }
543         while (rset_read (rset, rfd, &key, &term_index));
544         score = (*rc->calc) (handle, psysno);
545         resultSetInsertRank (zh, sort_info, psysno, score, 'A');
546         (*rc->end) (zh, handle);
547     }
548     rset_close (rset, rfd);
549     logf (LOG_DEBUG, "%d keys, %d distinct sysnos", kno, *hits);
550 }
551
552 ZebraRankClass zebraRankLookup (ZebraHandle zh, const char *name)
553 {
554     ZebraRankClass p = zh->rank_classes;
555     while (p && strcmp (p->control->name, name))
556         p = p->next;
557     if (p && !p->init_flag)
558     {
559         if (p->control->create)
560             p->class_handle = (*p->control->create)(zh);
561         p->init_flag = 1;
562     }
563     return p;
564 }
565
566 void zebraRankInstall (ZebraHandle zh, struct rank_control *ctrl)
567 {
568     ZebraRankClass p = xmalloc (sizeof(*p));
569     p->control = xmalloc (sizeof(*p->control));
570     memcpy (p->control, ctrl, sizeof(*p->control));
571     p->control->name = xstrdup (ctrl->name);
572     p->init_flag = 0;
573     p->next = zh->rank_classes;
574     zh->rank_classes = p;
575 }
576
577 void zebraRankDestroy (ZebraHandle zh)
578 {
579     ZebraRankClass p = zh->rank_classes;
580     while (p)
581     {
582         ZebraRankClass p_next = p->next;
583         if (p->init_flag && p->control->destroy)
584             (*p->control->destroy)(zh, p->class_handle);
585         xfree (p->control->name);
586         xfree (p->control);
587         xfree (p);
588         p = p_next;
589     }
590     zh->rank_classes = NULL;
591 }