2aeb0722020259248f06fb302c3bb189c990fb5b
[idzebra-moved-to-github.git] / index / zsets.c
1 /*
2  * Copyright (C) 1994-2002, Index Data
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Id: zsets.c,v 1.33 2002-03-20 20:24:30 adam Exp $
7  */
8 #include <stdio.h>
9 #include <assert.h>
10 #ifdef WIN32
11 #include <io.h>
12 #else
13 #include <unistd.h>
14 #endif
15
16 #include "zserver.h"
17 #include <rstemp.h>
18
19 #define SORT_IDX_ENTRYSIZE 64
20 #define ZSET_SORT_MAX_LEVEL 3
21
22 struct zebra_set_term_entry {
23     int reg_type;
24     char *db;
25     int set;
26     int use;
27     char *term;
28 };
29 struct zebra_set {
30     char *name;
31     RSET rset;
32     NMEM nmem;
33     int hits;
34     int num_bases;
35     char **basenames;
36     Z_RPNQuery *rpn;
37     struct zset_sort_info *sort_info;
38     struct zebra_set_term_entry *term_entries;
39     int term_entries_max;
40     struct zebra_set *next;
41     int locked;
42 };
43
44 struct zset_sort_entry {
45     int sysno;
46     int score;
47     char buf[ZSET_SORT_MAX_LEVEL][SORT_IDX_ENTRYSIZE];
48 };
49
50 struct zset_sort_info {
51     int max_entries;
52     int num_entries;
53     struct zset_sort_entry *all_entries;
54     struct zset_sort_entry **entries;
55 };
56
57 ZebraSet resultSetAddRPN (ZebraHandle zh, ODR input, ODR output,
58                           Z_RPNQuery *rpn, int num_bases, char **basenames, 
59                           const char *setname)
60 {
61     ZebraSet zebraSet;
62
63     zh->errCode = 0;
64     zh->errString = NULL;
65     zh->hits = 0;
66
67     zebraSet = resultSetAdd (zh, setname, 1);
68     if (!zebraSet)
69         return 0;
70     zebraSet->locked = 1;
71     zebraSet->rpn = 0;
72     zebraSet->num_bases = num_bases;
73     zebraSet->basenames = basenames;
74     zebraSet->nmem = odr_extract_mem (input);
75
76     zebraSet->rset = rpn_search (zh, output->mem, rpn,
77                                  zebraSet->num_bases,
78                                  zebraSet->basenames, zebraSet->name,
79                                  zebraSet);
80     zh->hits = zebraSet->hits;
81     if (zebraSet->rset)
82         zebraSet->rpn = rpn;
83     zebraSet->locked = 0;
84     return zebraSet;
85 }
86
87 void resultSetAddTerm (ZebraHandle zh, ZebraSet s, int reg_type,
88                        const char *db, int set,
89                        int use, const char *term)
90 {
91     if (!s->nmem)
92         s->nmem = nmem_create ();
93     if (!s->term_entries)
94     {
95         int i;
96         s->term_entries_max = 1000;
97         s->term_entries =
98             nmem_malloc (s->nmem, s->term_entries_max * 
99                          sizeof(*s->term_entries));
100         for (i = 0; i < s->term_entries_max; i++)
101             s->term_entries[i].term = 0;
102     }
103     if (s->hits < s->term_entries_max)
104     {
105         s->term_entries[s->hits].reg_type = reg_type;
106         s->term_entries[s->hits].db = nmem_strdup (s->nmem, db);
107         s->term_entries[s->hits].set = set;
108         s->term_entries[s->hits].use = use;
109         s->term_entries[s->hits].term = nmem_strdup (s->nmem, term);
110     }
111     (s->hits)++;
112 }
113
114
115 const char *zebra_resultSetTerms (ZebraHandle zh, const char *setname, 
116                                   int no, int *count, int *no_max)
117 {
118     ZebraSet s = resultSetGet (zh, setname);
119
120     *count = 0;
121     *no_max = 0;
122     if (!s || !s->rset)
123         return 0;
124     *no_max = s->rset->no_rset_terms;
125     if (no < 0 || no >= *no_max)
126         return 0;
127     *count = s->rset->rset_terms[no]->count;
128     return s->rset->rset_terms[no]->name;
129 }
130
131
132 ZebraSet resultSetAdd (ZebraHandle zh, const char *name, int ov)
133 {
134     ZebraSet s;
135     int i;
136
137     for (s = zh->sets; s; s = s->next)
138         if (!strcmp (s->name, name))
139             break;
140     if (s)
141     {
142         logf (LOG_DEBUG, "updating result set %s", name);
143         if (!ov || s->locked)
144             return NULL;
145         if (s->rset)
146             rset_delete (s->rset);
147         if (s->nmem)
148             nmem_destroy (s->nmem);
149     }
150     else
151     {
152         logf (LOG_DEBUG, "adding result set %s", name);
153         s = (ZebraSet) xmalloc (sizeof(*s));
154         s->next = zh->sets;
155         zh->sets = s;
156         s->name = (char *) xmalloc (strlen(name)+1);
157         strcpy (s->name, name);
158
159         s->sort_info = (struct zset_sort_info *)
160             xmalloc (sizeof(*s->sort_info));
161         s->sort_info->max_entries = 1000;
162         s->sort_info->entries = (struct zset_sort_entry **)
163             xmalloc (sizeof(*s->sort_info->entries) *
164                      s->sort_info->max_entries);
165         s->sort_info->all_entries = (struct zset_sort_entry *)
166             xmalloc (sizeof(*s->sort_info->all_entries) *
167                      s->sort_info->max_entries);
168         for (i = 0; i < s->sort_info->max_entries; i++)
169             s->sort_info->entries[i] = s->sort_info->all_entries + i;
170     }
171     s->locked = 0;
172     s->term_entries = 0;
173     s->hits = 0;
174     s->rset = 0;
175     s->nmem = 0;
176     s->rpn = 0;
177     return s;
178 }
179
180 ZebraSet resultSetGet (ZebraHandle zh, const char *name)
181 {
182     ZebraSet s;
183
184     for (s = zh->sets; s; s = s->next)
185         if (!strcmp (s->name, name))
186         {
187             if (!s->term_entries && !s->rset && s->rpn)
188             {
189                 NMEM nmem = nmem_create ();
190                 yaz_log (LOG_LOG, "research %s", name);
191                 s->rset =
192                     rpn_search (zh, nmem, s->rpn, s->num_bases,
193                                 s->basenames, s->name, s);
194                 nmem_destroy (nmem);
195             }
196             return s;
197         }
198     return NULL;
199 }
200
201 void resultSetInvalidate (ZebraHandle zh)
202 {
203     ZebraSet s = zh->sets;
204     
205     for (; s; s = s->next)
206     {
207         if (s->rset)
208             rset_delete (s->rset);
209         s->rset = 0;
210     }
211 }
212
213 void resultSetDestroy (ZebraHandle zh, int num, char **names,int *statuses)
214 {
215     ZebraSet * ss = &zh->sets;
216     int i;
217     
218     if (statuses)
219         for (i = 0; i<num; i++)
220             statuses[i] = Z_DeleteStatus_resultSetDidNotExist;
221     zh->errCode = 0;
222     zh->errString = NULL;
223     while (*ss)
224     {
225         int i = -1;
226         ZebraSet s = *ss;
227         if (num >= 0)
228         {
229             for (i = 0; i<num; i++)
230                 if (!strcmp (s->name, names[i]))
231                 {
232                     if (statuses)
233                         statuses[i] = Z_DeleteStatus_success;
234                     i = -1;
235                     break;
236                 }
237         }
238         if (i < 0)
239         {
240             *ss = s->next;
241             
242             xfree (s->sort_info->all_entries);
243             xfree (s->sort_info->entries);
244             xfree (s->sort_info);
245             
246             if (s->nmem)
247                 nmem_destroy (s->nmem);
248             if (s->rset)
249                 rset_delete (s->rset);
250             xfree (s->name);
251             xfree (s);
252         }
253         else
254             ss = &s->next;
255     }
256 }
257
258 ZebraPosSet zebraPosSetCreate (ZebraHandle zh, const char *name, 
259                                int num, int *positions)
260 {
261     ZebraSet sset;
262     ZebraPosSet sr = 0;
263     RSET rset;
264     int i;
265     struct zset_sort_info *sort_info;
266
267     if (!(sset = resultSetGet (zh, name)))
268         return NULL;
269     if (!(rset = sset->rset))
270     {
271         if (!sset->term_entries)
272             return 0;
273         sr = (ZebraPosSet) xmalloc (sizeof(*sr) * num);
274         for (i = 0; i<num; i++)
275         {
276             struct zebra_set_term_entry *entry = sset->term_entries;
277
278             sr[i].sysno = 0;
279             sr[i].score = -1;
280             sr[i].term = 0;
281             sr[i].db = 0;
282
283             if (positions[i] <= sset->term_entries_max)
284             {
285                 sr[i].term = sset->term_entries[positions[i]-1].term;
286                 sr[i].db = sset->term_entries[positions[i]-1].db;
287             }
288         }
289     }
290     else
291     {
292         sr = (ZebraPosSet) xmalloc (sizeof(*sr) * num);
293         for (i = 0; i<num; i++)
294         {
295             sr[i].sysno = 0;
296             sr[i].score = -1;
297             sr[i].term = 0;
298             sr[i].db = 0;
299         }
300         sort_info = sset->sort_info;
301         if (sort_info)
302         {
303             int position;
304             
305             for (i = 0; i<num; i++)
306             {
307                 position = positions[i];
308                 if (position > 0 && position <= sort_info->num_entries)
309                 {
310                     logf (LOG_DEBUG, "got pos=%d (sorted)", position);
311                     sr[i].sysno = sort_info->entries[position-1]->sysno;
312                     sr[i].score = sort_info->entries[position-1]->score;
313                 }
314             }
315         }
316         /* did we really get all entries using sort ? */
317         for (i = 0; i<num; i++)
318         {
319             if (!sr[i].sysno)
320                 break;
321         }
322         if (i < num) /* nope, get the rest, unsorted - sorry */
323         {
324             int position = 0;
325             int num_i = 0;
326             int psysno = 0;
327             int term_index;
328             RSFD rfd;
329             struct it_key key;
330             
331             if (sort_info)
332                 position = sort_info->num_entries;
333             while (num_i < num && positions[num_i] < position)
334                 num_i++;
335             rfd = rset_open (rset, RSETF_READ);
336             while (num_i < num && rset_read (rset, rfd, &key, &term_index))
337             {
338                 if (key.sysno != psysno)
339                 {
340                     psysno = key.sysno;
341                     if (sort_info)
342                     {
343                         /* determine we alreay have this in our set */
344                         for (i = sort_info->num_entries; --i >= 0; )
345                             if (psysno == sort_info->entries[i]->sysno)
346                                 break;
347                         if (i >= 0)
348                             continue;
349                     }
350                     position++;
351                     assert (num_i < num);
352                     if (position == positions[num_i])
353                     {
354                         sr[num_i].sysno = psysno;
355                         logf (LOG_DEBUG, "got pos=%d (unsorted)", position);
356                         sr[num_i].score = -1;
357                         num_i++;
358                     }
359                 }
360             }
361             rset_close (rset, rfd);
362         }
363     }
364     return sr;
365 }
366
367 void zebraPosSetDestroy (ZebraHandle zh, ZebraPosSet records, int num)
368 {
369     xfree (records);
370 }
371
372 struct sortKeyInfo {
373     int relation;
374     int attrUse;
375     int numerical;
376 };
377
378 void resultSetInsertSort (ZebraHandle zh, ZebraSet sset,
379                           struct sortKeyInfo *criteria, int num_criteria,
380                           int sysno)
381 {
382     struct zset_sort_entry this_entry;
383     struct zset_sort_entry *new_entry = NULL;
384     struct zset_sort_info *sort_info = sset->sort_info;
385     int i, j;
386
387     sortIdx_sysno (zh->service->sortIdx, sysno);
388     for (i = 0; i<num_criteria; i++)
389     {
390         sortIdx_type (zh->service->sortIdx, criteria[i].attrUse);
391         sortIdx_read (zh->service->sortIdx, this_entry.buf[i]);
392     }
393     i = sort_info->num_entries;
394     while (--i >= 0)
395     {
396         int rel = 0;
397         for (j = 0; j<num_criteria; j++)
398         {
399             if (criteria[j].numerical)
400             {
401                 double diff = atof(this_entry.buf[j]) -
402                               atof(sort_info->entries[i]->buf[j]);
403                 rel = 0;
404                 if (diff > 0.0)
405                     rel = 1;
406                 else if (diff < 0.0)
407                     rel = -1;
408             }
409             else
410             {
411                 rel = memcmp (this_entry.buf[j], sort_info->entries[i]->buf[j],
412                           SORT_IDX_ENTRYSIZE);
413             }
414             if (rel)
415                 break;
416         }       
417         if (!rel)
418             break;
419         if (criteria[j].relation == 'A')
420         {
421             if (rel > 0)
422                 break;
423         }
424         else if (criteria[j].relation == 'D')
425         {
426             if (rel < 0)
427                 break;
428         }
429     }
430     ++i;
431     j = sort_info->max_entries;
432     if (i == j)
433         return;
434
435     if (sort_info->num_entries == j)
436         --j;
437     else
438         j = (sort_info->num_entries)++;
439     new_entry = sort_info->entries[j];
440     while (j != i)
441     {
442         sort_info->entries[j] = sort_info->entries[j-1];
443         --j;
444     }
445     sort_info->entries[i] = new_entry;
446     assert (new_entry);
447     for (i = 0; i<num_criteria; i++)
448         memcpy (new_entry->buf[i], this_entry.buf[i], SORT_IDX_ENTRYSIZE);
449     new_entry->sysno = sysno;
450     new_entry->score = -1;
451 }
452
453 void resultSetInsertRank (ZebraHandle zh, struct zset_sort_info *sort_info,
454                           int sysno, int score, int relation)
455 {
456     struct zset_sort_entry *new_entry = NULL;
457     int i, j;
458
459     i = sort_info->num_entries;
460     while (--i >= 0)
461     {
462         int rel = 0;
463
464         rel = score - sort_info->entries[i]->score;
465
466         if (relation == 'D')
467         {
468             if (rel >= 0)
469                 break;
470         }
471         else if (relation == 'A')
472         {
473             if (rel <= 0)
474                 break;
475         }
476     }
477     ++i;
478     j = sort_info->max_entries;
479     if (i == j)
480         return;
481
482     if (sort_info->num_entries == j)
483         --j;
484     else
485         j = (sort_info->num_entries)++;
486     
487     new_entry = sort_info->entries[j];
488     while (j != i)
489     {
490         sort_info->entries[j] = sort_info->entries[j-1];
491         --j;
492     }
493     sort_info->entries[i] = new_entry;
494     assert (new_entry);
495     new_entry->sysno = sysno;
496     new_entry->score = score;
497 }
498
499 void resultSetSort (ZebraHandle zh, NMEM nmem,
500                     int num_input_setnames, const char **input_setnames,
501                     const char *output_setname,
502                     Z_SortKeySpecList *sort_sequence, int *sort_status)
503 {
504     ZebraSet sset;
505     RSET rset;
506
507     if (num_input_setnames == 0)
508     {
509         zh->errCode = 208;
510         return ;
511     }
512     if (num_input_setnames > 1)
513     {
514         zh->errCode = 230;
515         return;
516     }
517     logf (LOG_DEBUG, "result set sort input=%s output=%s",
518           *input_setnames, output_setname);
519     sset = resultSetGet (zh, input_setnames[0]);
520     if (!sset)
521     {
522         zh->errCode = 30;
523         zh->errString = nmem_strdup (nmem, input_setnames[0]);
524         return;
525     }
526     if (!(rset = sset->rset))
527     {
528         zh->errCode = 30;
529         zh->errString = nmem_strdup (nmem, input_setnames[0]);
530         return;
531     }
532     if (strcmp (output_setname, input_setnames[0]))
533     {
534         rset = rset_dup (rset);
535         sset = resultSetAdd (zh, output_setname, 1);
536         sset->rset = rset;
537     }
538     resultSetSortSingle (zh, nmem, sset, rset, sort_sequence, sort_status);
539 }
540
541 void resultSetSortSingle (ZebraHandle zh, NMEM nmem,
542                           ZebraSet sset, RSET rset,
543                           Z_SortKeySpecList *sort_sequence, int *sort_status)
544 {
545     int i, psysno = 0;
546     struct it_key key;
547     struct sortKeyInfo sort_criteria[3];
548     int num_criteria;
549     int term_index;
550     RSFD rfd;
551
552     logf (LOG_LOG, "resultSetSortSingle start");
553     sset->sort_info->num_entries = 0;
554
555     sset->hits = 0;
556     num_criteria = sort_sequence->num_specs;
557     if (num_criteria > 3)
558         num_criteria = 3;
559     for (i = 0; i < num_criteria; i++)
560     {
561         Z_SortKeySpec *sks = sort_sequence->specs[i];
562         Z_SortKey *sk;
563
564         if (*sks->sortRelation == Z_SortRelation_ascending)
565             sort_criteria[i].relation = 'A';
566         else if (*sks->sortRelation == Z_SortRelation_descending)
567             sort_criteria[i].relation = 'D';
568         else
569         {
570             zh->errCode = 214;
571             return;
572         }
573         if (sks->sortElement->which == Z_SortElement_databaseSpecific)
574         {
575             zh->errCode = 210;
576             return;
577         }
578         else if (sks->sortElement->which != Z_SortElement_generic)
579         {
580             zh->errCode = 237;
581             return;
582         }       
583         sk = sks->sortElement->u.generic;
584         switch (sk->which)
585         {
586         case Z_SortKey_sortField:
587             logf (LOG_DEBUG, "Sort: key %d is of type sortField", i+1);
588             zh->errCode = 207;
589             return;
590         case Z_SortKey_elementSpec:
591             logf (LOG_DEBUG, "Sort: key %d is of type elementSpec", i+1);
592             zh->errCode = 207;
593             return;
594         case Z_SortKey_sortAttributes:
595             logf (LOG_DEBUG, "Sort: key %d is of type sortAttributes", i+1);
596             sort_criteria[i].attrUse =
597                 zebra_maps_sort (zh->service->zebra_maps,
598                                  sk->u.sortAttributes,
599                                  &sort_criteria[i].numerical);
600             logf (LOG_DEBUG, "use value = %d", sort_criteria[i].attrUse);
601             if (sort_criteria[i].attrUse == -1)
602             {
603                 zh->errCode = 116;
604                 return;
605             }
606             if (sortIdx_type (zh->service->sortIdx, sort_criteria[i].attrUse))
607             {
608                 zh->errCode = 207;
609                 return;
610             }
611             break;
612         }
613     }
614     rfd = rset_open (rset, RSETF_READ);
615     while (rset_read (rset, rfd, &key, &term_index))
616     {
617         if (key.sysno != psysno)
618         {
619             (sset->hits)++;
620             psysno = key.sysno;
621             resultSetInsertSort (zh, sset,
622                                  sort_criteria, num_criteria, psysno);
623         }
624     }
625     rset_close (rset, rfd);
626
627     for (i = 0; i < rset->no_rset_terms; i++)
628         yaz_log (LOG_LOG, "term=\"%s\" nn=%d type=%s count=%d",
629                  rset->rset_terms[i]->name,
630                  rset->rset_terms[i]->nn,
631                  rset->rset_terms[i]->flags,
632                  rset->rset_terms[i]->count);
633
634     *sort_status = Z_SortStatus_success;
635     logf (LOG_LOG, "resultSetSortSingle end");
636 }
637
638 RSET resultSetRef (ZebraHandle zh, Z_ResultSetId *resultSetId)
639 {
640     ZebraSet s;
641
642     if ((s = resultSetGet (zh, resultSetId)))
643         return s->rset;
644     return NULL;
645 }
646
647 void resultSetRank (ZebraHandle zh, ZebraSet zebraSet, RSET rset)
648 {
649     int kno = 0;
650     struct it_key key;
651     RSFD rfd;
652     int term_index, i;
653     ZebraRankClass rank_class;
654     struct rank_control *rc;
655     struct zset_sort_info *sort_info;
656
657     sort_info = zebraSet->sort_info;
658     sort_info->num_entries = 0;
659     zebraSet->hits = 0;
660     rfd = rset_open (rset, RSETF_READ);
661
662     yaz_log (LOG_LOG, "resultSetRank");
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
694     for (i = 0; i < rset->no_rset_terms; i++)
695         yaz_log (LOG_LOG, "term=\"%s\" nn=%d type=%s count=%d",
696                  rset->rset_terms[i]->name,
697                  rset->rset_terms[i]->nn,
698                  rset->rset_terms[i]->flags,
699                  rset->rset_terms[i]->count);
700     
701     yaz_log (LOG_LOG, "%d keys, %d distinct sysnos", kno, zebraSet->hits);
702 }
703
704 ZebraRankClass zebraRankLookup (ZebraHandle zh, const char *name)
705 {
706     ZebraRankClass p = zh->service->rank_classes;
707     while (p && strcmp (p->control->name, name))
708         p = p->next;
709     if (p && !p->init_flag)
710     {
711         if (p->control->create)
712             p->class_handle = (*p->control->create)(zh->service);
713         p->init_flag = 1;
714     }
715     return p;
716 }
717
718 void zebraRankInstall (ZebraService zh, struct rank_control *ctrl)
719 {
720     ZebraRankClass p = (ZebraRankClass) xmalloc (sizeof(*p));
721     p->control = (struct rank_control *) xmalloc (sizeof(*p->control));
722     memcpy (p->control, ctrl, sizeof(*p->control));
723     p->control->name = xstrdup (ctrl->name);
724     p->init_flag = 0;
725     p->next = zh->rank_classes;
726     zh->rank_classes = p;
727 }
728
729 void zebraRankDestroy (ZebraService zh)
730 {
731     ZebraRankClass p = zh->rank_classes;
732     while (p)
733     {
734         ZebraRankClass p_next = p->next;
735         if (p->init_flag && p->control->destroy)
736             (*p->control->destroy)(zh, p->class_handle);
737         xfree (p->control->name);
738         xfree (p->control);
739         xfree (p);
740         p = p_next;
741     }
742     zh->rank_classes = NULL;
743 }