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