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