Added snippet utilities and snippet window implementation.
[idzebra-moved-to-github.git] / index / zsets.c
1 /* $Id: zsets.c,v 1.87 2005-06-07 11:36:38 adam Exp $
2    Copyright (C) 1995-2005
3    Index Data ApS
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22
23
24 #include <stdio.h>
25 #include <assert.h>
26 #ifdef WIN32
27 #include <io.h>
28 #else
29 #include <unistd.h>
30 #endif
31
32 #include "index.h"
33 #include <yaz/diagbib1.h>
34 #include <rset.h>
35
36 #define SORT_IDX_ENTRYSIZE 64
37 #define ZSET_SORT_MAX_LEVEL 3
38
39 struct zebra_set_term_entry {
40     int reg_type;
41     char *db;
42     int set;
43     int use;
44     char *term;
45 };
46
47 struct zebra_set {
48     char *name;
49     RSET rset;
50     NMEM nmem;
51     NMEM rset_nmem; /* for creating the rsets in */
52     zint hits;
53     int num_bases;
54     char **basenames;
55     Z_RPNQuery *rpn;
56     struct zset_sort_info *sort_info;
57     struct zebra_set_term_entry *term_entries;
58     int term_entries_max;
59     struct zebra_set *next;
60     int locked;
61
62     zint cache_position;  /* last position */
63     RSFD cache_rfd;       /* rfd (NULL if not existing) */
64     zint cache_psysno;    /* sysno for last position */
65 };
66
67 struct zset_sort_entry {
68     zint sysno;
69     int score;
70     char buf[ZSET_SORT_MAX_LEVEL][SORT_IDX_ENTRYSIZE];
71 };
72
73 struct zset_sort_info {
74     int max_entries;
75     int num_entries;
76     struct zset_sort_entry *all_entries;
77     struct zset_sort_entry **entries;
78 };
79
80 static int log_level_set=0;
81 static int log_level_sort=0;
82 static int log_level_searchhits=0;
83 static int log_level_searchterms=0;
84 static int log_level_resultsets=0;
85
86 static void loglevels()
87 {
88     if (log_level_set)
89         return;
90     log_level_sort = yaz_log_module_level("sorting");
91     log_level_searchhits = yaz_log_module_level("searchhits");
92     log_level_searchterms = yaz_log_module_level("searchterms");
93     log_level_resultsets = yaz_log_module_level("resultsets");
94     log_level_set = 1;
95 }
96
97 ZEBRA_RES resultSetSearch(ZebraHandle zh, NMEM nmem, NMEM rset_nmem,
98                           Z_RPNQuery *rpn, ZebraSet sset)
99 {
100     RSET rset = 0;
101     oident *attrset;
102     Z_SortKeySpecList *sort_sequence;
103     int sort_status, i;
104     ZEBRA_RES res = ZEBRA_OK;
105
106     zh->hits = 0;
107
108     sort_sequence = (Z_SortKeySpecList *)
109         nmem_malloc(nmem, sizeof(*sort_sequence));
110     sort_sequence->num_specs = 10; /* FIXME - Hard-coded number */
111     sort_sequence->specs = (Z_SortKeySpec **)
112         nmem_malloc(nmem, sort_sequence->num_specs *
113                      sizeof(*sort_sequence->specs));
114     for (i = 0; i<sort_sequence->num_specs; i++)
115         sort_sequence->specs[i] = 0;
116     
117     attrset = oid_getentbyoid (rpn->attributeSetId);
118     res = rpn_search_top(zh, rpn->RPNStructure, attrset->value,
119                          nmem, rset_nmem,
120                          sort_sequence,
121                          sset->num_bases, sset->basenames,
122                          &rset);
123     if (res != ZEBRA_OK)
124     {
125         sset->rset = 0;
126         return res;
127     }
128     for (i = 0; sort_sequence->specs[i]; i++)
129         ;
130     sort_sequence->num_specs = i;
131     if (!i)
132     {
133         res = resultSetRank (zh, sset, rset, rset_nmem);
134     }
135     else
136     {
137         res = resultSetSortSingle (zh, nmem, sset, rset,
138                                    sort_sequence, &sort_status);
139     }
140     sset->rset = rset;
141     return res;
142 }
143
144
145 ZEBRA_RES resultSetAddRPN (ZebraHandle zh, NMEM m, Z_RPNQuery *rpn,
146                            int num_bases, char **basenames,
147                            const char *setname)
148 {
149     ZebraSet zebraSet;
150     int i;
151     ZEBRA_RES res;
152
153     zh->hits = 0;
154
155     zebraSet = resultSetAdd (zh, setname, 1);
156     if (!zebraSet)
157         return ZEBRA_FAIL;
158     zebraSet->locked = 1;
159     zebraSet->rpn = 0;
160     zebraSet->nmem = m;
161     zebraSet->rset_nmem = nmem_create(); 
162
163     zebraSet->num_bases = num_bases;
164     zebraSet->basenames = 
165         nmem_malloc (zebraSet->nmem, num_bases * sizeof(*zebraSet->basenames));
166     for (i = 0; i<num_bases; i++)
167         zebraSet->basenames[i] = nmem_strdup (zebraSet->nmem, basenames[i]);
168
169     res = resultSetSearch(zh, zebraSet->nmem, zebraSet->rset_nmem,
170                           rpn, zebraSet);
171     zh->hits = zebraSet->hits;
172     if (zebraSet->rset)
173         zebraSet->rpn = rpn;
174     zebraSet->locked = 0;
175     if (!zebraSet->rset)
176         return ZEBRA_FAIL;
177     return res;
178 }
179
180 void resultSetAddTerm (ZebraHandle zh, ZebraSet s, int reg_type,
181                        const char *db, int set,
182                        int use, const char *term)
183 {
184     assert(zh); /* compiler shut up */
185     if (!s->nmem)
186         s->nmem = nmem_create ();
187     if (!s->term_entries)
188     {
189         int i;
190         s->term_entries_max = 1000;
191         s->term_entries =
192             nmem_malloc (s->nmem, s->term_entries_max * 
193                          sizeof(*s->term_entries));
194         for (i = 0; i < s->term_entries_max; i++)
195             s->term_entries[i].term = 0;
196     }
197     if (s->hits < s->term_entries_max)
198     {
199         s->term_entries[s->hits].reg_type = reg_type;
200         s->term_entries[s->hits].db = nmem_strdup (s->nmem, db);
201         s->term_entries[s->hits].set = set;
202         s->term_entries[s->hits].use = use;
203         s->term_entries[s->hits].term = nmem_strdup (s->nmem, term);
204     }
205     (s->hits)++;
206 }
207
208 ZebraSet resultSetAdd (ZebraHandle zh, const char *name, int ov)
209 {
210     ZebraSet s;
211     int i;
212
213     for (s = zh->sets; s; s = s->next)
214         if (!strcmp (s->name, name))
215             break;
216     
217     if (!log_level_set)
218         loglevels();
219     if (s)
220     {
221         yaz_log(log_level_resultsets, "updating result set %s", name);
222         if (!ov || s->locked)
223             return NULL;
224         if (s->rset)
225         {
226             if (s->cache_rfd)
227                 rset_close(s->cache_rfd);
228             rset_delete (s->rset);
229         }
230         if (s->rset_nmem)
231             nmem_destroy (s->rset_nmem);
232         if (s->nmem)
233             nmem_destroy (s->nmem);
234     }
235     else
236     {
237         const char *sort_max_str = zebra_get_resource(zh, "sortmax", "1000");
238
239         yaz_log(log_level_resultsets, "adding result set %s", name);
240         s = (ZebraSet) xmalloc (sizeof(*s));
241         s->next = zh->sets;
242         zh->sets = s;
243         s->name = (char *) xmalloc (strlen(name)+1);
244         strcpy (s->name, name);
245
246         s->sort_info = (struct zset_sort_info *)
247             xmalloc (sizeof(*s->sort_info));
248         s->sort_info->max_entries = atoi(sort_max_str);
249         if (s->sort_info->max_entries < 2)
250             s->sort_info->max_entries = 2;
251
252         s->sort_info->entries = (struct zset_sort_entry **)
253             xmalloc (sizeof(*s->sort_info->entries) *
254                      s->sort_info->max_entries);
255         s->sort_info->all_entries = (struct zset_sort_entry *)
256             xmalloc (sizeof(*s->sort_info->all_entries) *
257                      s->sort_info->max_entries);
258         for (i = 0; i < s->sort_info->max_entries; i++)
259             s->sort_info->entries[i] = s->sort_info->all_entries + i;
260     }
261     s->locked = 0;
262     s->term_entries = 0;
263     s->hits = 0;
264     s->rset = 0;
265     s->rset_nmem = 0;
266     s->nmem = 0;
267     s->rpn = 0;
268     s->cache_position = 0;
269     s->cache_rfd = 0;
270     return s;
271 }
272
273 ZebraSet resultSetGet (ZebraHandle zh, const char *name)
274 {
275     ZebraSet s;
276
277     for (s = zh->sets; s; s = s->next)
278         if (!strcmp (s->name, name))
279         {
280             if (!s->term_entries && !s->rset && s->rpn)
281             {
282                 NMEM nmem = nmem_create ();
283                 yaz_log(log_level_resultsets, "research %s", name);
284                 if (!s->rset_nmem)
285                     s->rset_nmem=nmem_create();
286                 resultSetSearch(zh, nmem, s->rset_nmem, s->rpn, s);
287                 nmem_destroy (nmem);
288             }
289             return s;
290         }
291     return NULL;
292 }
293
294 void resultSetInvalidate (ZebraHandle zh)
295 {
296     ZebraSet s = zh->sets;
297     
298     yaz_log(log_level_resultsets, "invalidating result sets");
299     for (; s; s = s->next)
300     {
301         if (s->rset)
302         {
303             if (s->cache_rfd)
304                 rset_close(s->cache_rfd);
305             rset_delete (s->rset);
306         }
307         s->rset = 0;
308         s->cache_rfd = 0;
309         s->cache_position = 0;
310         if (s->rset_nmem)
311             nmem_destroy(s->rset_nmem);
312         s->rset_nmem=0;
313     }
314 }
315
316 void resultSetDestroy (ZebraHandle zh, int num, char **names,int *statuses)
317 {
318     ZebraSet * ss = &zh->sets;
319     int i;
320     
321     if (statuses)
322         for (i = 0; i<num; i++)
323             statuses[i] = Z_DeleteStatus_resultSetDidNotExist;
324     while (*ss)
325     {
326         int i = -1;
327         ZebraSet s = *ss;
328         if (num >= 0)
329         {
330             for (i = 0; i<num; i++)
331                 if (!strcmp (s->name, names[i]))
332                 {
333                     if (statuses)
334                         statuses[i] = Z_DeleteStatus_success;
335                     i = -1;
336                     break;
337                 }
338         }
339         if (i < 0)
340         {
341             *ss = s->next;
342             
343             xfree (s->sort_info->all_entries);
344             xfree (s->sort_info->entries);
345             xfree (s->sort_info);
346             
347             if (s->nmem)
348                 nmem_destroy (s->nmem);
349             if (s->rset)
350             {
351                 if (s->cache_rfd)
352                     rset_close(s->cache_rfd);
353                 rset_delete (s->rset);
354             }
355             if (s->rset_nmem)
356                 nmem_destroy(s->rset_nmem);
357             xfree (s->name);
358             xfree (s);
359         }
360         else
361             ss = &s->next;
362     }
363 }
364
365 ZebraMetaRecord *zebra_meta_records_create_range(ZebraHandle zh,
366                                                  const char *name, 
367                                                  zint start, int num)
368 {
369     zint pos_small[10];
370     zint *pos = pos_small;
371     ZebraMetaRecord *mr;
372     int i;
373
374     if (num > 10000 || num <= 0)
375         return 0;
376
377     if (num > 10)
378         pos = xmalloc(sizeof(*pos) * num);
379     
380     for (i = 0; i<num; i++)
381         pos[i] = start+i;
382
383     mr = zebra_meta_records_create(zh, name, num, pos);
384     
385     if (num > 10)
386         xfree(pos);
387     return mr;
388 }
389
390 ZebraMetaRecord *zebra_meta_records_create(ZebraHandle zh, const char *name, 
391                                            int num, zint *positions)
392 {
393     ZebraSet sset;
394     ZebraMetaRecord *sr = 0;
395     RSET rset;
396     int i;
397     struct zset_sort_info *sort_info;
398
399     if (!log_level_set)
400         loglevels();
401     if (!(sset = resultSetGet (zh, name)))
402         return NULL;
403     if (!(rset = sset->rset))
404     {
405         if (!sset->term_entries)
406             return 0;
407         sr = (ZebraMetaRecord *) xmalloc (sizeof(*sr) * num);
408         for (i = 0; i<num; i++)
409         {
410             sr[i].sysno = 0;
411             sr[i].score = -1;
412             sr[i].term = 0;
413             sr[i].db = 0;
414
415             if (positions[i] <= sset->term_entries_max)
416             {
417                 sr[i].term = sset->term_entries[positions[i]-1].term;
418                 sr[i].db = sset->term_entries[positions[i]-1].db;
419             }
420         }
421     }
422     else
423     {
424         sr = (ZebraMetaRecord *) xmalloc (sizeof(*sr) * num);
425         for (i = 0; i<num; i++)
426         {
427             sr[i].sysno = 0;
428             sr[i].score = -1;
429             sr[i].term = 0;
430             sr[i].db = 0;
431         }
432         sort_info = sset->sort_info;
433         if (sort_info)
434         {
435             zint position;
436             
437             for (i = 0; i<num; i++)
438             {
439                 position = positions[i];
440                 if (position > 0 && position <= sort_info->num_entries)
441                 {
442                     yaz_log(log_level_sort, "got pos=" ZINT_FORMAT
443                             " (sorted)", position);
444                     sr[i].sysno = sort_info->entries[position-1]->sysno;
445                     sr[i].score = sort_info->entries[position-1]->score;
446                 }
447             }
448         }
449         /* did we really get all entries using sort ? */
450         for (i = 0; i<num; i++)
451         {
452             if (!sr[i].sysno)
453                 break;
454         }
455         if (i < num) /* nope, get the rest, unsorted - sorry */
456         {
457             zint position = 0;
458             int num_i = 0;
459             zint psysno = 0;
460             RSFD rfd;
461             struct it_key key;
462             
463             if (sort_info)
464                 position = sort_info->num_entries;
465             while (num_i < num && positions[num_i] <= position)
466                 num_i++;
467             
468             if (sset->cache_rfd &&
469                 num_i < num && positions[num_i] > sset->cache_position)
470             {
471                 position = sset->cache_position;
472                 rfd = sset->cache_rfd;
473                 psysno = sset->cache_psysno;
474             }
475             else
476             {
477                 if (sset->cache_rfd)
478                     rset_close(sset->cache_rfd);
479                 rfd = rset_open (rset, RSETF_READ);
480             }
481             while (num_i < num && rset_read (rfd, &key, 0))
482             {
483                 zint this_sys = key.mem[0];
484                 if (this_sys != psysno)
485                 {
486                     psysno = this_sys;
487                     if (sort_info)
488                     {
489                         /* determine we alreay have this in our set */
490                         for (i = sort_info->num_entries; --i >= 0; )
491                             if (psysno == sort_info->entries[i]->sysno)
492                                 break;
493                         if (i >= 0)
494                             continue;
495                     }
496                     position++;
497                     assert (num_i < num);
498                     if (position == positions[num_i])
499                     {
500                         sr[num_i].sysno = psysno;
501                         yaz_log(log_level_sort, "got pos=" ZINT_FORMAT " (unsorted)", position);
502                         sr[num_i].score = -1;
503                         num_i++;
504                     }
505                 }
506             }
507             sset->cache_position = position;
508             sset->cache_psysno = psysno;
509             sset->cache_rfd = rfd;
510         }
511     }
512     return sr;
513 }
514
515 void zebra_meta_records_destroy (ZebraHandle zh, ZebraMetaRecord *records,
516                                  int num)
517 {
518     assert(zh); /* compiler shut up about unused arg */
519     xfree (records);
520 }
521
522 struct sortKeyInfo {
523     int relation;
524     int attrUse;
525     int numerical;
526 };
527
528 void resultSetInsertSort (ZebraHandle zh, ZebraSet sset,
529                           struct sortKeyInfo *criteria, int num_criteria,
530                           zint sysno)
531 {
532     struct zset_sort_entry this_entry;
533     struct zset_sort_entry *new_entry = NULL;
534     struct zset_sort_info *sort_info = sset->sort_info;
535     int i, j;
536
537     sortIdx_sysno (zh->reg->sortIdx, sysno);
538     for (i = 0; i<num_criteria; i++)
539     {
540         sortIdx_type (zh->reg->sortIdx, criteria[i].attrUse);
541         sortIdx_read (zh->reg->sortIdx, this_entry.buf[i]);
542     }
543     i = sort_info->num_entries;
544     while (--i >= 0)
545     {
546         int rel = 0;
547         for (j = 0; j<num_criteria; j++)
548         {
549             if (criteria[j].numerical)
550             {
551                 double diff = atof(this_entry.buf[j]) -
552                               atof(sort_info->entries[i]->buf[j]);
553                 rel = 0;
554                 if (diff > 0.0)
555                     rel = 1;
556                 else if (diff < 0.0)
557                     rel = -1;
558             }
559             else
560             {
561                 rel = memcmp (this_entry.buf[j], sort_info->entries[i]->buf[j],
562                           SORT_IDX_ENTRYSIZE);
563             }
564             if (rel)
565                 break;
566         }       
567         if (!rel)
568             break;
569         if (criteria[j].relation == 'A')
570         {
571             if (rel > 0)
572                 break;
573         }
574         else if (criteria[j].relation == 'D')
575         {
576             if (rel < 0)
577                 break;
578         }
579     }
580     ++i;
581     j = sort_info->max_entries;
582     if (i == j)
583         return;
584
585     if (sort_info->num_entries == j)
586         --j;
587     else
588         j = (sort_info->num_entries)++;
589     new_entry = sort_info->entries[j];
590     while (j != i)
591     {
592         sort_info->entries[j] = sort_info->entries[j-1];
593         --j;
594     }
595     sort_info->entries[i] = new_entry;
596     assert (new_entry);
597     for (i = 0; i<num_criteria; i++)
598         memcpy (new_entry->buf[i], this_entry.buf[i], SORT_IDX_ENTRYSIZE);
599     new_entry->sysno = sysno;
600     new_entry->score = -1;
601 }
602
603 void resultSetInsertRank (ZebraHandle zh, struct zset_sort_info *sort_info,
604                           zint sysno, int score, int relation)
605 {
606     struct zset_sort_entry *new_entry = NULL;
607     int i, j;
608     assert(zh); /* compiler shut up about unused arg */
609
610     i = sort_info->num_entries;
611     while (--i >= 0)
612     {
613         int rel = 0;
614
615         rel = score - sort_info->entries[i]->score;
616
617         if (relation == 'D')
618         {
619             if (rel >= 0)
620                 break;
621         }
622         else if (relation == 'A')
623         {
624             if (rel <= 0)
625                 break;
626         }
627     }
628     ++i;
629     j = sort_info->max_entries;
630     if (i == j)
631         return;
632
633     if (sort_info->num_entries == j)
634         --j;
635     else
636         j = (sort_info->num_entries)++;
637     
638     new_entry = sort_info->entries[j];
639     while (j != i)
640     {
641         sort_info->entries[j] = sort_info->entries[j-1];
642         --j;
643     }
644     sort_info->entries[i] = new_entry;
645     assert (new_entry);
646     new_entry->sysno = sysno;
647     new_entry->score = score;
648 }
649
650 ZEBRA_RES resultSetSort(ZebraHandle zh, NMEM nmem,
651                         int num_input_setnames, const char **input_setnames,
652                         const char *output_setname,
653                         Z_SortKeySpecList *sort_sequence, int *sort_status)
654 {
655     ZebraSet sset;
656     RSET rset;
657
658     if (num_input_setnames == 0)
659     {
660         zebra_setError(zh, YAZ_BIB1_NO_RESULT_SET_NAME_SUPPLIED_ON_SORT, 0);
661         return ZEBRA_FAIL;
662     }
663     if (num_input_setnames > 1)
664     {
665         zebra_setError(zh, YAZ_BIB1_SORT_TOO_MANY_INPUT_RESULTS, 0);
666         return ZEBRA_FAIL;
667     }
668     if (!log_level_set)
669         loglevels();
670     yaz_log(log_level_sort, "result set sort input=%s output=%s",
671           *input_setnames, output_setname);
672     sset = resultSetGet (zh, input_setnames[0]);
673     if (!sset)
674     {
675         zebra_setError(zh, YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST,
676                        input_setnames[0]);
677         return ZEBRA_FAIL;
678     }
679     if (!(rset = sset->rset))
680     {
681         zebra_setError(zh, YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST,
682                        input_setnames[0]);
683         return ZEBRA_FAIL;
684     }
685     if (strcmp (output_setname, input_setnames[0]))
686     {
687         rset = rset_dup (rset);
688         sset = resultSetAdd (zh, output_setname, 1);
689         sset->rset = rset;
690     }
691     return resultSetSortSingle (zh, nmem, sset, rset, sort_sequence,
692                                 sort_status);
693 }
694
695 ZEBRA_RES resultSetSortSingle(ZebraHandle zh, NMEM nmem,
696                               ZebraSet sset, RSET rset,
697                               Z_SortKeySpecList *sort_sequence,
698                               int *sort_status)
699 {
700     int i;
701     int n = 0;
702     zint kno = 0;
703     zint psysno = 0;
704     struct it_key key;
705     struct sortKeyInfo sort_criteria[3];
706     int num_criteria;
707     RSFD rfd;
708     TERMID termid;
709     TERMID *terms;
710     int numTerms = 0;
711
712     assert(nmem); /* compiler shut up about unused param */
713     sset->sort_info->num_entries = 0;
714
715     rset_getterms(rset, 0, 0, &n);
716     terms = (TERMID *) nmem_malloc(nmem, sizeof(*terms)*n);
717     rset_getterms(rset, terms, n, &numTerms);
718
719     sset->hits = 0;
720     num_criteria = sort_sequence->num_specs;
721     if (num_criteria > 3)
722         num_criteria = 3;
723     for (i = 0; i < num_criteria; i++)
724     {
725         Z_SortKeySpec *sks = sort_sequence->specs[i];
726         Z_SortKey *sk;
727
728         if (*sks->sortRelation == Z_SortKeySpec_ascending)
729             sort_criteria[i].relation = 'A';
730         else if (*sks->sortRelation == Z_SortKeySpec_descending)
731             sort_criteria[i].relation = 'D';
732         else
733         {
734             zebra_setError(zh, YAZ_BIB1_ILLEGAL_SORT_RELATION, 0);
735             return ZEBRA_FAIL;
736         }
737         if (sks->sortElement->which == Z_SortElement_databaseSpecific)
738         {
739             zebra_setError(zh, YAZ_BIB1_DATABASE_SPECIFIC_SORT_UNSUPP, 0);
740             return ZEBRA_FAIL;
741         }
742         else if (sks->sortElement->which != Z_SortElement_generic)
743         {
744             zebra_setError(zh, YAZ_BIB1_SORT_ILLEGAL_SORT, 0);
745             return ZEBRA_FAIL;
746         }       
747         sk = sks->sortElement->u.generic;
748         switch (sk->which)
749         {
750         case Z_SortKey_sortField:
751             yaz_log(log_level_sort, "key %d is of type sortField",
752                     i+1);
753             zebra_setError(zh, YAZ_BIB1_CANNOT_SORT_ACCORDING_TO_SEQUENCE, 0);
754             return ZEBRA_FAIL;
755         case Z_SortKey_elementSpec:
756             yaz_log(log_level_sort, "key %d is of type elementSpec",
757                     i+1);
758             zebra_setError(zh, YAZ_BIB1_CANNOT_SORT_ACCORDING_TO_SEQUENCE, 0);
759             return ZEBRA_FAIL;
760         case Z_SortKey_sortAttributes:
761             yaz_log(log_level_sort, "key %d is of type sortAttributes", i+1);
762             sort_criteria[i].attrUse =
763                 zebra_maps_sort (zh->reg->zebra_maps,
764                                  sk->u.sortAttributes,
765                                  &sort_criteria[i].numerical);
766             yaz_log(log_level_sort, "use value = %d", sort_criteria[i].attrUse);
767             if (sort_criteria[i].attrUse == -1)
768             {
769                 zebra_setError(
770                     zh, YAZ_BIB1_USE_ATTRIBUTE_REQUIRED_BUT_NOT_SUPPLIED, 0); 
771                 return ZEBRA_FAIL;
772             }
773             if (sortIdx_type (zh->reg->sortIdx, sort_criteria[i].attrUse))
774             {
775                 zebra_setError(
776                     zh, YAZ_BIB1_CANNOT_SORT_ACCORDING_TO_SEQUENCE, 0);
777                 return ZEBRA_FAIL;
778             }
779             break;
780         }
781     }
782     rfd = rset_open (rset, RSETF_READ);
783     while (rset_read (rfd, &key, &termid))
784     {
785         zint this_sys = key.mem[0];
786         if (log_level_searchhits)
787             key_logdump_txt(log_level_searchhits, &key, termid->name);
788         kno++;
789         if (this_sys != psysno)
790         {
791             (sset->hits)++;
792             psysno = this_sys;
793             resultSetInsertSort (zh, sset,
794                                  sort_criteria, num_criteria, psysno);
795         }
796     }
797     rset_close (rfd);
798     yaz_log(log_level_sort, ZINT_FORMAT " keys, " ZINT_FORMAT " sysnos, sort",
799             kno, sset->hits);   
800     for (i = 0; i < numTerms; i++)
801         yaz_log(log_level_sort, "term=\"%s\" type=%s count=" ZINT_FORMAT,
802                  terms[i]->name, terms[i]->flags, terms[i]->rset->hits_count);
803     *sort_status = Z_SortResponse_success;
804     return ZEBRA_OK;
805 }
806
807 RSET resultSetRef(ZebraHandle zh, const char *resultSetId)
808 {
809     ZebraSet s;
810
811     if ((s = resultSetGet (zh, resultSetId)))
812         return s->rset;
813     return NULL;
814 }
815
816 ZEBRA_RES resultSetRank(ZebraHandle zh, ZebraSet zebraSet,
817                         RSET rset, NMEM nmem)
818 {
819     struct it_key key;
820     TERMID termid;
821     TERMID *terms;
822     zint kno = 0;
823     int numTerms = 0;
824     int n = 0;
825     int i;
826     ZebraRankClass rank_class;
827     struct zset_sort_info *sort_info;
828     const char *rank_handler_name = res_get_def(zh->res, "rank", "rank-1");
829
830     if (!log_level_set)
831         loglevels();
832     sort_info = zebraSet->sort_info;
833     sort_info->num_entries = 0;
834     zebraSet->hits = 0;
835     rset_getterms(rset, 0, 0, &n);
836     terms = (TERMID *) nmem_malloc(nmem, sizeof(*terms)*n);
837     rset_getterms(rset, terms, n, &numTerms);
838
839     rank_class = zebraRankLookup(zh, rank_handler_name);
840     if (!rank_class)
841     {
842         yaz_log(YLOG_WARN, "No such rank handler: %s", rank_handler_name);
843         zebra_setError(zh, YAZ_BIB1_UNSUPP_SEARCH, "Cannot find rank handler");
844         return ZEBRA_FAIL;
845     }
846     else
847     {
848         RSFD rfd = rset_open(rset, RSETF_READ);
849         struct rank_control *rc = rank_class->control;
850         double score;
851         
852         void *handle =
853             (*rc->begin) (zh->reg, rank_class->class_handle, rset, nmem,
854                           terms, numTerms);
855         zint psysno = 0;
856         while (rset_read(rfd, &key, &termid))
857         {
858             zint this_sys = key.mem[0];
859             zint seqno = key.mem[key.len-1];
860             kno++;
861             if (log_level_searchhits)
862                 key_logdump_txt(log_level_searchhits, &key, termid->name);
863             if (this_sys != psysno)
864             {
865                 if (rfd->counted_items >= rset->hits_limit)
866                     break;
867                 if (psysno)
868                 {
869                     score = (*rc->calc) (handle, psysno);
870                     resultSetInsertRank (zh, sort_info, psysno, score, 'A');
871                 }
872                 psysno = this_sys;
873             }
874             (*rc->add) (handle, CAST_ZINT_TO_INT(seqno), termid);
875         }
876         if (psysno)
877         {
878             score = (*rc->calc)(handle, psysno);
879             resultSetInsertRank(zh, sort_info, psysno, score, 'A');
880         }
881         (*rc->end) (zh->reg, handle);
882         rset_close (rfd);
883     }
884     zebraSet->hits = rset->hits_count;
885
886     yaz_log(log_level_searchterms, ZINT_FORMAT " keys, "
887             ZINT_FORMAT " sysnos, rank",  kno, zebraSet->hits);
888     for (i = 0; i < numTerms; i++)
889     {
890         yaz_log(log_level_searchterms, "term=\"%s\" type=%s count="
891                 ZINT_FORMAT,
892                 terms[i]->name, terms[i]->flags, terms[i]->rset->hits_count);
893     }
894     return ZEBRA_OK;
895 }
896
897 ZebraRankClass zebraRankLookup(ZebraHandle zh, const char *name)
898 {
899     ZebraRankClass p = zh->reg->rank_classes;
900     while (p && strcmp (p->control->name, name))
901         p = p->next;
902     if (p && !p->init_flag)
903     {
904         if (p->control->create)
905             p->class_handle = (*p->control->create)(zh);
906         p->init_flag = 1;
907     }
908     return p;
909 }
910
911 void zebraRankInstall(struct zebra_register *reg, struct rank_control *ctrl)
912 {
913     ZebraRankClass p = (ZebraRankClass) xmalloc (sizeof(*p));
914     p->control = (struct rank_control *) xmalloc (sizeof(*p->control));
915     memcpy (p->control, ctrl, sizeof(*p->control));
916     p->control->name = xstrdup (ctrl->name);
917     p->init_flag = 0;
918     p->next = reg->rank_classes;
919     reg->rank_classes = p;
920 }
921
922 void zebraRankDestroy(struct zebra_register *reg)
923 {
924     ZebraRankClass p = reg->rank_classes;
925     while (p)
926     {
927         ZebraRankClass p_next = p->next;
928         if (p->init_flag && p->control->destroy)
929             (*p->control->destroy)(reg, p->class_handle);
930         xfree(p->control->name);
931         xfree(p->control);
932         xfree(p);
933         p = p_next;
934     }
935     reg->rank_classes = NULL;
936 }
937
938 static int trav_rset_for_termids(RSET rset, TERMID *termid_array,
939                                  zint *hits_array, int *approx_array)
940 {
941     int no = 0;
942     int i;
943     for (i = 0; i<rset->no_children; i++)
944         no += trav_rset_for_termids(rset->children[i],
945                                     (termid_array ? termid_array + no : 0),
946                                     (hits_array ? hits_array + no : 0),
947                                     (approx_array ? approx_array + no : 0));
948     if (rset->term)
949     {
950         if (termid_array)
951             termid_array[no] = rset->term;
952         if (hits_array)
953             hits_array[no] = rset->hits_count;
954         if (approx_array)
955             approx_array[no] = rset->hits_approx;
956 #if 0
957         yaz_log(YLOG_LOG, "rset=%p term=%s count=" ZINT_FORMAT,
958                 rset, rset->term->name, rset->hits_count);
959 #endif
960         no++;
961     }
962     return no;
963 }
964
965 ZEBRA_RES zebra_result_set_term_no(ZebraHandle zh, const char *setname,
966                                    int *num_terms)
967 {
968     ZebraSet sset = resultSetGet(zh, setname);
969     *num_terms = 0;
970     if (sset)
971     {
972         *num_terms = trav_rset_for_termids(sset->rset, 0, 0, 0);
973         return ZEBRA_OK;
974     }
975     return ZEBRA_FAIL;
976 }
977
978 ZEBRA_RES zebra_result_set_term_info(ZebraHandle zh, const char *setname,
979                                      int no, zint *count, int *approx,
980                                      char *termbuf, size_t *termlen)
981 {
982     ZebraSet sset = resultSetGet(zh, setname);
983     if (sset)
984     {
985         int num_terms = trav_rset_for_termids(sset->rset, 0, 0, 0);
986         if (no >= 0 && no < num_terms)
987         {
988             TERMID *term_array = xmalloc(num_terms * sizeof(*term_array));
989             zint *hits_array = xmalloc(num_terms * sizeof(*hits_array));
990             int *approx_array = xmalloc(num_terms * sizeof(*approx_array));
991             
992             trav_rset_for_termids(sset->rset, term_array,
993                                   hits_array, approx_array);
994
995             if (count)
996                 *count = hits_array[no];
997             if (approx)
998                 *approx = approx_array[no];
999             if (termbuf)
1000             {
1001                 char *inbuf = term_array[no]->name;
1002                 size_t inleft = strlen(inbuf);
1003                 size_t outleft = *termlen - 1;
1004
1005                 if (zh->iconv_from_utf8 != 0)
1006                 {
1007                     char *outbuf = termbuf;
1008                     size_t ret;
1009                     
1010                     ret = yaz_iconv(zh->iconv_from_utf8, &inbuf, &inleft,
1011                                     &outbuf, &outleft);
1012                     if (ret == (size_t)(-1))
1013                         *termlen = 0;
1014                     else
1015                         *termlen = outbuf - termbuf;
1016                 }
1017                 else
1018                 {
1019                     if (inleft > outleft)
1020                         inleft = outleft;
1021                     *termlen = inleft;
1022                     memcpy(termbuf, inbuf, *termlen);
1023                 }
1024                 termbuf[*termlen] = '\0';
1025             }
1026
1027             xfree(term_array);
1028             xfree(hits_array);
1029             xfree(approx_array);
1030             return ZEBRA_OK;
1031         }
1032     }
1033     return ZEBRA_FAIL;
1034 }
1035
1036 ZEBRA_RES zebra_snippets_hit_vector(ZebraHandle zh, const char *setname,
1037                                     zint sysno, zebra_snippets *snippets)
1038 {
1039     ZebraSet sset = resultSetGet(zh, setname);
1040     yaz_log(YLOG_LOG, "zebra_get_hit_vector setname=%s zysno=" ZINT_FORMAT,
1041             setname, sysno);
1042     if (!sset)
1043         return ZEBRA_FAIL;
1044     else
1045     {
1046         struct rset_key_control *kc = zebra_key_control_create(zh);
1047         NMEM nmem = nmem_create();
1048         struct it_key key;
1049         RSET rsets[2], rset_comb;
1050         RSET rset_temp = rstemp_create(nmem, kc, kc->scope, 
1051                                        res_get (zh->res, "setTmpDir"),0 );
1052         
1053         TERMID termid;
1054         RSFD rsfd = rset_open(rset_temp, RSETF_WRITE);
1055         
1056         key.mem[0] = sysno;
1057         key.mem[1] = 0;
1058         key.mem[2] = 0;
1059         key.mem[3] = 0;
1060         key.len = 2;
1061         rset_write (rsfd, &key);
1062         rset_close (rsfd);
1063
1064         rsets[0] = rset_temp;
1065         rsets[1] = rset_dup(sset->rset);
1066         
1067         rset_comb = rsmulti_and_create(nmem, kc, kc->scope, 2, rsets);
1068
1069         rsfd = rset_open(rset_comb, RSETF_READ);
1070
1071         while (rset_read(rsfd, &key, &termid))
1072         {
1073             if (termid)
1074             {
1075                 struct ord_list *ol;
1076                 key_logdump_txt(YLOG_LOG, &key, termid->name);
1077                 for (ol = termid->ol; ol; ol = ol->next)
1078                 {
1079                     yaz_log(YLOG_LOG, "   ord=%d", ol->ord);
1080                     zebra_snippets_append(snippets, key.mem[key.len-1],
1081                                           ol->ord, termid->name);
1082                 }
1083             }
1084         }
1085         rset_close(rsfd);
1086         
1087         rset_delete(rset_comb);
1088         nmem_destroy(nmem);
1089     }
1090     return ZEBRA_OK;
1091 }
1092