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