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