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