Optimize multiple binary ANDs + OPs to multi ANDs, ORs.
[idzebra-moved-to-github.git] / index / zsets.c
1 /* $Id: zsets.c,v 1.81 2005-04-25 11:54:08 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 <rset.h>
34
35 #define SORT_IDX_ENTRYSIZE 64
36 #define ZSET_SORT_MAX_LEVEL 3
37
38 struct zebra_set_term_entry {
39     int reg_type;
40     char *db;
41     int set;
42     int use;
43     char *term;
44 };
45 struct zebra_set {
46     char *name;
47     RSET rset;
48     NMEM nmem;
49     NMEM rset_nmem; /* for creating the rsets in */
50     zint hits;
51     int num_bases;
52     char **basenames;
53     Z_RPNQuery *rpn;
54     struct zset_sort_info *sort_info;
55     struct zebra_set_term_entry *term_entries;
56     int term_entries_max;
57     struct zebra_set *next;
58     int locked;
59
60     zint cache_position;  /* last position */
61     RSFD cache_rfd;       /* rfd (NULL if not existing) */
62     zint cache_psysno;    /* sysno for last position */
63 };
64
65 struct zset_sort_entry {
66     zint sysno;
67     int score;
68     char buf[ZSET_SORT_MAX_LEVEL][SORT_IDX_ENTRYSIZE];
69 };
70
71 struct zset_sort_info {
72     int max_entries;
73     int num_entries;
74     struct zset_sort_entry *all_entries;
75     struct zset_sort_entry **entries;
76 };
77
78 static int log_level_set=0;
79 static int log_level_sorting=0;
80 static int log_level_searchhits=0;
81 static int log_level_searchterms=0;
82 static int log_level_resultsets=0;
83
84 static void loglevels()
85 {
86     if (log_level_set)
87         return;
88     log_level_sorting = yaz_log_module_level("sorting");
89     log_level_searchhits = yaz_log_module_level("searchhits");
90     log_level_searchterms = yaz_log_module_level("searchterms");
91     log_level_resultsets = yaz_log_module_level("resultsets");
92     log_level_set = 1;
93 }
94
95 ZEBRA_RES resultSetSearch(ZebraHandle zh, NMEM nmem, NMEM rset_nmem,
96                           Z_RPNQuery *rpn, ZebraSet sset)
97 {
98     RSET rset = 0;
99     oident *attrset;
100     Z_SortKeySpecList *sort_sequence;
101     int sort_status, i;
102     ZEBRA_RES res;
103
104     zh->errCode = 0;
105     zh->errString = NULL;
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
129     if (zh->errCode)
130         yaz_log(YLOG_DEBUG, "search error: %d", zh->errCode);
131     
132     for (i = 0; sort_sequence->specs[i]; i++)
133         ;
134     sort_sequence->num_specs = i;
135     if (!i)
136         resultSetRank (zh, sset, rset, rset_nmem);
137     else
138     {
139         yaz_log(YLOG_DEBUG, "resultSetSortSingle in rpn_search");
140         resultSetSortSingle (zh, nmem, sset, rset,
141                              sort_sequence, &sort_status);
142         if (zh->errCode)
143         {
144             yaz_log(YLOG_DEBUG, "resultSetSortSingle status = %d", zh->errCode);
145         }
146     }
147     sset->rset = rset;
148     return ZEBRA_OK;
149 }
150
151
152 ZEBRA_RES resultSetAddRPN (ZebraHandle zh, NMEM m, Z_RPNQuery *rpn,
153                            int num_bases, char **basenames,
154                            const char *setname)
155 {
156     ZebraSet zebraSet;
157     int i;
158     ZEBRA_RES res;
159
160     zh->errCode = 0;
161     zh->errString = NULL;
162     zh->hits = 0;
163
164     zebraSet = resultSetAdd (zh, setname, 1);
165     if (!zebraSet)
166         return ZEBRA_FAIL;
167     zebraSet->locked = 1;
168     zebraSet->rpn = 0;
169     zebraSet->nmem = m;
170     zebraSet->rset_nmem = nmem_create(); 
171
172     zebraSet->num_bases = num_bases;
173     zebraSet->basenames = 
174         nmem_malloc (zebraSet->nmem, num_bases * sizeof(*zebraSet->basenames));
175     for (i = 0; i<num_bases; i++)
176         zebraSet->basenames[i] = nmem_strdup (zebraSet->nmem, basenames[i]);
177
178     res = resultSetSearch(zh, zebraSet->nmem, zebraSet->rset_nmem,
179                           rpn, zebraSet);
180     zh->hits = zebraSet->hits;
181     if (zebraSet->rset)
182         zebraSet->rpn = rpn;
183     zebraSet->locked = 0;
184     if (!zebraSet->rset)
185         return ZEBRA_FAIL;
186     return res;
187 }
188
189 void resultSetAddTerm (ZebraHandle zh, ZebraSet s, int reg_type,
190                        const char *db, int set,
191                        int use, const char *term)
192 {
193     assert(zh); /* compiler shut up */
194     if (!s->nmem)
195         s->nmem = nmem_create ();
196     if (!s->term_entries)
197     {
198         int i;
199         s->term_entries_max = 1000;
200         s->term_entries =
201             nmem_malloc (s->nmem, s->term_entries_max * 
202                          sizeof(*s->term_entries));
203         for (i = 0; i < s->term_entries_max; i++)
204             s->term_entries[i].term = 0;
205     }
206     if (s->hits < s->term_entries_max)
207     {
208         s->term_entries[s->hits].reg_type = reg_type;
209         s->term_entries[s->hits].db = nmem_strdup (s->nmem, db);
210         s->term_entries[s->hits].set = set;
211         s->term_entries[s->hits].use = use;
212         s->term_entries[s->hits].term = nmem_strdup (s->nmem, term);
213     }
214     (s->hits)++;
215 }
216
217 ZebraSet resultSetAdd (ZebraHandle zh, const char *name, int ov)
218 {
219     ZebraSet s;
220     int i;
221
222     for (s = zh->sets; s; s = s->next)
223         if (!strcmp (s->name, name))
224             break;
225     
226     if (!log_level_set)
227         loglevels();
228     if (s)
229     {
230         yaz_log(log_level_resultsets, "updating result set %s", name);
231         if (!ov || s->locked)
232             return NULL;
233         if (s->rset)
234         {
235             if (s->cache_rfd)
236                 rset_close(s->cache_rfd);
237             rset_delete (s->rset);
238         }
239         if (s->rset_nmem)
240             nmem_destroy (s->rset_nmem);
241         if (s->nmem)
242             nmem_destroy (s->nmem);
243     }
244     else
245     {
246         const char *sort_max_str = zebra_get_resource(zh, "sortmax", "1000");
247
248         yaz_log(log_level_resultsets, "adding result set %s", name);
249         s = (ZebraSet) xmalloc (sizeof(*s));
250         s->next = zh->sets;
251         zh->sets = s;
252         s->name = (char *) xmalloc (strlen(name)+1);
253         strcpy (s->name, name);
254
255         s->sort_info = (struct zset_sort_info *)
256             xmalloc (sizeof(*s->sort_info));
257         s->sort_info->max_entries = atoi(sort_max_str);
258         if (s->sort_info->max_entries < 2)
259             s->sort_info->max_entries = 2;
260
261         s->sort_info->entries = (struct zset_sort_entry **)
262             xmalloc (sizeof(*s->sort_info->entries) *
263                      s->sort_info->max_entries);
264         s->sort_info->all_entries = (struct zset_sort_entry *)
265             xmalloc (sizeof(*s->sort_info->all_entries) *
266                      s->sort_info->max_entries);
267         for (i = 0; i < s->sort_info->max_entries; i++)
268             s->sort_info->entries[i] = s->sort_info->all_entries + i;
269     }
270     s->locked = 0;
271     s->term_entries = 0;
272     s->hits = 0;
273     s->rset = 0;
274     s->rset_nmem = 0;
275     s->nmem = 0;
276     s->rpn = 0;
277     s->cache_position = 0;
278     s->cache_rfd = 0;
279     return s;
280 }
281
282 ZebraSet resultSetGet (ZebraHandle zh, const char *name)
283 {
284     ZebraSet s;
285
286     for (s = zh->sets; s; s = s->next)
287         if (!strcmp (s->name, name))
288         {
289             if (!s->term_entries && !s->rset && s->rpn)
290             {
291                 NMEM nmem = nmem_create ();
292                 yaz_log(log_level_resultsets, "research %s", name);
293                 if (!s->rset_nmem)
294                     s->rset_nmem=nmem_create();
295                 resultSetSearch(zh, nmem, s->rset_nmem, s->rpn, s);
296                 nmem_destroy (nmem);
297             }
298             return s;
299         }
300     return NULL;
301 }
302
303 void resultSetInvalidate (ZebraHandle zh)
304 {
305     ZebraSet s = zh->sets;
306     
307     yaz_log(log_level_resultsets, "invalidating result sets");
308     for (; s; s = s->next)
309     {
310         if (s->rset)
311         {
312             if (s->cache_rfd)
313                 rset_close(s->cache_rfd);
314             rset_delete (s->rset);
315         }
316         s->rset = 0;
317         s->cache_rfd = 0;
318         s->cache_position = 0;
319         if (s->rset_nmem)
320             nmem_destroy(s->rset_nmem);
321         s->rset_nmem=0;
322     }
323 }
324
325 void resultSetDestroy (ZebraHandle zh, int num, char **names,int *statuses)
326 {
327     ZebraSet * ss = &zh->sets;
328     int i;
329     
330     if (statuses)
331         for (i = 0; i<num; i++)
332             statuses[i] = Z_DeleteStatus_resultSetDidNotExist;
333     zh->errCode = 0;
334     zh->errString = NULL;
335     while (*ss)
336     {
337         int i = -1;
338         ZebraSet s = *ss;
339         if (num >= 0)
340         {
341             for (i = 0; i<num; i++)
342                 if (!strcmp (s->name, names[i]))
343                 {
344                     if (statuses)
345                         statuses[i] = Z_DeleteStatus_success;
346                     i = -1;
347                     break;
348                 }
349         }
350         if (i < 0)
351         {
352             *ss = s->next;
353             
354             xfree (s->sort_info->all_entries);
355             xfree (s->sort_info->entries);
356             xfree (s->sort_info);
357             
358             if (s->nmem)
359                 nmem_destroy (s->nmem);
360             if (s->rset)
361             {
362                 if (s->cache_rfd)
363                     rset_close(s->cache_rfd);
364                 rset_delete (s->rset);
365             }
366             if (s->rset_nmem)
367                 nmem_destroy(s->rset_nmem);
368             xfree (s->name);
369             xfree (s);
370         }
371         else
372             ss = &s->next;
373     }
374 }
375
376 ZebraMetaRecord *zebra_meta_records_create_range (ZebraHandle zh,
377                                                   const char *name, 
378                                                   zint start, int num)
379 {
380     zint pos_small[10];
381     zint *pos = pos_small;
382     ZebraMetaRecord *mr;
383     int i;
384
385     if (num > 10000 || num <= 0)
386         return 0;
387
388     if (num > 10)
389         pos = xmalloc(sizeof(*pos) * num);
390     
391     for (i = 0; i<num; i++)
392         pos[i] = start+i;
393
394     mr = zebra_meta_records_create(zh, name, num, pos);
395     
396     if (num > 10)
397         xfree(pos);
398     return mr;
399 }
400
401 ZebraMetaRecord *zebra_meta_records_create (ZebraHandle zh, const char *name, 
402                                             int num, zint *positions)
403 {
404     ZebraSet sset;
405     ZebraMetaRecord *sr = 0;
406     RSET rset;
407     int i;
408     struct zset_sort_info *sort_info;
409
410     if (!log_level_set)
411         loglevels();
412     if (!(sset = resultSetGet (zh, name)))
413         return NULL;
414     if (!(rset = sset->rset))
415     {
416         if (!sset->term_entries)
417             return 0;
418         sr = (ZebraMetaRecord *) xmalloc (sizeof(*sr) * num);
419         for (i = 0; i<num; i++)
420         {
421             sr[i].sysno = 0;
422             sr[i].score = -1;
423             sr[i].term = 0;
424             sr[i].db = 0;
425
426             if (positions[i] <= sset->term_entries_max)
427             {
428                 sr[i].term = sset->term_entries[positions[i]-1].term;
429                 sr[i].db = sset->term_entries[positions[i]-1].db;
430             }
431         }
432     }
433     else
434     {
435         sr = (ZebraMetaRecord *) xmalloc (sizeof(*sr) * num);
436         for (i = 0; i<num; i++)
437         {
438             sr[i].sysno = 0;
439             sr[i].score = -1;
440             sr[i].term = 0;
441             sr[i].db = 0;
442         }
443         sort_info = sset->sort_info;
444         if (sort_info)
445         {
446             zint position;
447             
448             for (i = 0; i<num; i++)
449             {
450                 position = positions[i];
451                 if (position > 0 && position <= sort_info->num_entries)
452                 {
453                     yaz_log(log_level_sorting, "got pos=" ZINT_FORMAT
454                             " (sorted)", position);
455                     sr[i].sysno = sort_info->entries[position-1]->sysno;
456                     sr[i].score = sort_info->entries[position-1]->score;
457                 }
458             }
459         }
460         /* did we really get all entries using sort ? */
461         for (i = 0; i<num; i++)
462         {
463             if (!sr[i].sysno)
464                 break;
465         }
466         if (i < num) /* nope, get the rest, unsorted - sorry */
467         {
468             zint position = 0;
469             int num_i = 0;
470             zint psysno = 0;
471             RSFD rfd;
472             struct it_key key;
473             
474             if (sort_info)
475                 position = sort_info->num_entries;
476             while (num_i < num && positions[num_i] <= position)
477                 num_i++;
478             
479             if (sset->cache_rfd &&
480                 num_i < num && positions[num_i] > sset->cache_position)
481             {
482                 position = sset->cache_position;
483                 rfd = sset->cache_rfd;
484                 psysno = sset->cache_psysno;
485             }
486             else
487             {
488                 if (sset->cache_rfd)
489                     rset_close(sset->cache_rfd);
490                 rfd = rset_open (rset, RSETF_READ);
491             }
492             while (num_i < num && rset_read (rfd, &key, 0))
493             {
494                 zint this_sys = key.mem[0];
495                 if (this_sys != psysno)
496                 {
497                     psysno = this_sys;
498                     if (sort_info)
499                     {
500                         /* determine we alreay have this in our set */
501                         for (i = sort_info->num_entries; --i >= 0; )
502                             if (psysno == sort_info->entries[i]->sysno)
503                                 break;
504                         if (i >= 0)
505                             continue;
506                     }
507                     position++;
508                     assert (num_i < num);
509                     if (position == positions[num_i])
510                     {
511                         sr[num_i].sysno = psysno;
512                         yaz_log(log_level_sorting, "got pos=" ZINT_FORMAT " (unsorted)", position);
513                         sr[num_i].score = -1;
514                         num_i++;
515                     }
516                 }
517             }
518             sset->cache_position = position;
519             sset->cache_psysno = psysno;
520             sset->cache_rfd = rfd;
521         }
522     }
523     return sr;
524 }
525
526 void zebra_meta_records_destroy (ZebraHandle zh, ZebraMetaRecord *records,
527                                  int num)
528 {
529     assert(zh); /* compiler shut up about unused arg */
530     xfree (records);
531 }
532
533 struct sortKeyInfo {
534     int relation;
535     int attrUse;
536     int numerical;
537 };
538
539 void resultSetInsertSort (ZebraHandle zh, ZebraSet sset,
540                           struct sortKeyInfo *criteria, int num_criteria,
541                           zint sysno)
542 {
543     struct zset_sort_entry this_entry;
544     struct zset_sort_entry *new_entry = NULL;
545     struct zset_sort_info *sort_info = sset->sort_info;
546     int i, j;
547
548     sortIdx_sysno (zh->reg->sortIdx, sysno);
549     for (i = 0; i<num_criteria; i++)
550     {
551         sortIdx_type (zh->reg->sortIdx, criteria[i].attrUse);
552         sortIdx_read (zh->reg->sortIdx, this_entry.buf[i]);
553     }
554     i = sort_info->num_entries;
555     while (--i >= 0)
556     {
557         int rel = 0;
558         for (j = 0; j<num_criteria; j++)
559         {
560             if (criteria[j].numerical)
561             {
562                 double diff = atof(this_entry.buf[j]) -
563                               atof(sort_info->entries[i]->buf[j]);
564                 rel = 0;
565                 if (diff > 0.0)
566                     rel = 1;
567                 else if (diff < 0.0)
568                     rel = -1;
569             }
570             else
571             {
572                 rel = memcmp (this_entry.buf[j], sort_info->entries[i]->buf[j],
573                           SORT_IDX_ENTRYSIZE);
574             }
575             if (rel)
576                 break;
577         }       
578         if (!rel)
579             break;
580         if (criteria[j].relation == 'A')
581         {
582             if (rel > 0)
583                 break;
584         }
585         else if (criteria[j].relation == 'D')
586         {
587             if (rel < 0)
588                 break;
589         }
590     }
591     ++i;
592     j = sort_info->max_entries;
593     if (i == j)
594         return;
595
596     if (sort_info->num_entries == j)
597         --j;
598     else
599         j = (sort_info->num_entries)++;
600     new_entry = sort_info->entries[j];
601     while (j != i)
602     {
603         sort_info->entries[j] = sort_info->entries[j-1];
604         --j;
605     }
606     sort_info->entries[i] = new_entry;
607     assert (new_entry);
608     for (i = 0; i<num_criteria; i++)
609         memcpy (new_entry->buf[i], this_entry.buf[i], SORT_IDX_ENTRYSIZE);
610     new_entry->sysno = sysno;
611     new_entry->score = -1;
612 }
613
614 void resultSetInsertRank (ZebraHandle zh, struct zset_sort_info *sort_info,
615                           zint sysno, int score, int relation)
616 {
617     struct zset_sort_entry *new_entry = NULL;
618     int i, j;
619     assert(zh); /* compiler shut up about unused arg */
620
621     i = sort_info->num_entries;
622     while (--i >= 0)
623     {
624         int rel = 0;
625
626         rel = score - sort_info->entries[i]->score;
627
628         if (relation == 'D')
629         {
630             if (rel >= 0)
631                 break;
632         }
633         else if (relation == 'A')
634         {
635             if (rel <= 0)
636                 break;
637         }
638     }
639     ++i;
640     j = sort_info->max_entries;
641     if (i == j)
642         return;
643
644     if (sort_info->num_entries == j)
645         --j;
646     else
647         j = (sort_info->num_entries)++;
648     
649     new_entry = sort_info->entries[j];
650     while (j != i)
651     {
652         sort_info->entries[j] = sort_info->entries[j-1];
653         --j;
654     }
655     sort_info->entries[i] = new_entry;
656     assert (new_entry);
657     new_entry->sysno = sysno;
658     new_entry->score = score;
659 }
660
661 void resultSetSort (ZebraHandle zh, NMEM nmem,
662                     int num_input_setnames, const char **input_setnames,
663                     const char *output_setname,
664                     Z_SortKeySpecList *sort_sequence, int *sort_status)
665 {
666     ZebraSet sset;
667     RSET rset;
668
669     if (num_input_setnames == 0)
670     {
671         zh->errCode = 208;
672         return ;
673     }
674     if (num_input_setnames > 1)
675     {
676         zh->errCode = 230;
677         return;
678     }
679     if (!log_level_set)
680         loglevels();
681     yaz_log(log_level_sorting, "result set sort input=%s output=%s",
682           *input_setnames, output_setname);
683     sset = resultSetGet (zh, input_setnames[0]);
684     if (!sset)
685     {
686         zh->errCode = 30;
687         zh->errString = nmem_strdup (nmem, input_setnames[0]);
688         return;
689     }
690     if (!(rset = sset->rset))
691     {
692         zh->errCode = 30;
693         zh->errString = nmem_strdup (nmem, input_setnames[0]);
694         return;
695     }
696     if (strcmp (output_setname, input_setnames[0]))
697     {
698         rset = rset_dup (rset);
699         sset = resultSetAdd (zh, output_setname, 1);
700         sset->rset = rset;
701     }
702     resultSetSortSingle (zh, nmem, sset, rset, sort_sequence, sort_status);
703 }
704
705 void resultSetSortSingle (ZebraHandle zh, NMEM nmem,
706                           ZebraSet sset, RSET rset,
707                           Z_SortKeySpecList *sort_sequence, int *sort_status)
708 {
709     int i;
710     int n = 0;
711     zint kno = 0;
712     zint psysno = 0;
713     struct it_key key;
714     struct sortKeyInfo sort_criteria[3];
715     int num_criteria;
716     RSFD rfd;
717     TERMID termid;
718     TERMID *terms;
719     int numTerms = 0;
720
721     assert(nmem); /* compiler shut up about unused param */
722     sset->sort_info->num_entries = 0;
723
724     rset_getterms(rset, 0, 0, &n);
725     terms = (TERMID *) nmem_malloc(nmem, sizeof(*terms)*n);
726     rset_getterms(rset, terms, n, &numTerms);
727
728     sset->hits = 0;
729     num_criteria = sort_sequence->num_specs;
730     if (num_criteria > 3)
731         num_criteria = 3;
732     for (i = 0; i < num_criteria; i++)
733     {
734         Z_SortKeySpec *sks = sort_sequence->specs[i];
735         Z_SortKey *sk;
736
737         if (*sks->sortRelation == Z_SortKeySpec_ascending)
738             sort_criteria[i].relation = 'A';
739         else if (*sks->sortRelation == Z_SortKeySpec_descending)
740             sort_criteria[i].relation = 'D';
741         else
742         {
743             zh->errCode = 214;
744             return;
745         }
746         if (sks->sortElement->which == Z_SortElement_databaseSpecific)
747         {
748             zh->errCode = 210;
749             return;
750         }
751         else if (sks->sortElement->which != Z_SortElement_generic)
752         {
753             zh->errCode = 237;
754             return;
755         }       
756         sk = sks->sortElement->u.generic;
757         switch (sk->which)
758         {
759         case Z_SortKey_sortField:
760             yaz_log(log_level_sorting, "Sort: key %d is of type sortField", i+1);
761             zh->errCode = 207;
762             return;
763         case Z_SortKey_elementSpec:
764             yaz_log(log_level_sorting, "Sort: key %d is of type elementSpec", i+1);
765             zh->errCode = 207;
766             return;
767         case Z_SortKey_sortAttributes:
768             yaz_log(log_level_sorting, "Sort: key %d is of type sortAttributes", i+1);
769             sort_criteria[i].attrUse =
770                 zebra_maps_sort (zh->reg->zebra_maps,
771                                  sk->u.sortAttributes,
772                                  &sort_criteria[i].numerical);
773             yaz_log(log_level_sorting, "use value = %d", sort_criteria[i].attrUse);
774             if (sort_criteria[i].attrUse == -1)
775             {
776                 zh->errCode = 116;
777                 return;
778             }
779             if (sortIdx_type (zh->reg->sortIdx, sort_criteria[i].attrUse))
780             {
781                 zh->errCode = 207;
782                 return;
783             }
784             break;
785         }
786     }
787     rfd = rset_open (rset, RSETF_READ);
788     while (rset_read (rfd, &key, &termid))
789       /* FIXME - pass a TERMID *, and use it for something below !! */
790     {
791         zint this_sys = key.mem[0];
792         kno++;
793         if (this_sys != psysno)
794         {
795             (sset->hits)++;
796             psysno = this_sys;
797             resultSetInsertSort (zh, sset,
798                                  sort_criteria, num_criteria, psysno);
799         }
800     }
801     rset_close (rfd);
802     yaz_log(log_level_sorting, ZINT_FORMAT " keys, " ZINT_FORMAT " sysnos, sort",
803                     kno, sset->hits);   
804     for (i = 0; i < numTerms; i++)
805         yaz_log(log_level_sorting, "term=\"%s\" type=%s count=" ZINT_FORMAT,
806                  terms[i]->name, terms[i]->flags, rset_count(terms[i]->rset));
807     *sort_status = Z_SortResponse_success;
808 }
809
810 RSET resultSetRef (ZebraHandle zh, const char *resultSetId)
811 {
812     ZebraSet s;
813
814     if ((s = resultSetGet (zh, resultSetId)))
815         return s->rset;
816     return NULL;
817 }
818
819 void resultSetRank (ZebraHandle zh, ZebraSet zebraSet, RSET rset, NMEM nmem)
820 {
821     zint kno = 0;
822     struct it_key key;
823     RSFD rfd;
824     TERMID termid;
825     TERMID *terms;
826     int numTerms = 0;
827     int n = 0;
828     int i;
829     ZebraRankClass rank_class;
830     struct rank_control *rc;
831     struct zset_sort_info *sort_info;
832     const char *rank_handler_name = res_get_def(zh->res, "rank", "rank-1");
833     double cur,tot; 
834     zint est=-2; /* -2 not done, -1 can't do, >0 actual estimate*/
835     zint esthits;
836     double ratio;
837
838     if (!log_level_set)
839         loglevels();
840     sort_info = zebraSet->sort_info;
841     sort_info->num_entries = 0;
842     zebraSet->hits = 0;
843     rset_getterms(rset, 0, 0, &n);
844     terms = (TERMID *) nmem_malloc(nmem, sizeof(*terms)*n);
845     rset_getterms(rset, terms, n, &numTerms);
846
847     rfd = rset_open (rset, RSETF_READ);
848
849     rank_class = zebraRankLookup (zh, rank_handler_name);
850     if (!rank_class)
851     {
852         yaz_log(YLOG_WARN, "No such rank handler: %s", rank_handler_name);
853         return;
854     }
855     rc = rank_class->control;
856
857     if (rset_read (rfd, &key, &termid))
858     {
859         zint psysno = key.mem[0];
860         int score;
861         void *handle =
862             (*rc->begin) (zh->reg, rank_class->class_handle, rset, nmem,
863                           terms, numTerms);
864         (zebraSet->hits)++;
865         esthits = atoi(res_get_def(zh->res, "estimatehits","0"));
866         if (!esthits) 
867             est = -1; /* can not do */
868         do
869         {
870             zint this_sys = key.mem[0]; /* FIXME - assumes scope==2 */
871             zint seqno = key.mem[key.len-1]; /* FIXME - assumes scope==2 */
872             kno++;
873             key_logdump_txt(log_level_searchhits,&key," Got hit");
874             if (this_sys != psysno)
875             {
876                 score = (*rc->calc) (handle, psysno);
877
878                 resultSetInsertRank (zh, sort_info, psysno, score, 'A');
879                 (zebraSet->hits)++;
880                 psysno = this_sys;
881             }
882             (*rc->add) (handle, CAST_ZINT_TO_INT(seqno), termid);
883             
884             if ((est==-2) && (zebraSet->hits==esthits))
885             { /* time to estimate the hits */
886                 rset_pos(rfd,&cur,&tot); 
887                 if (tot>0) {
888                     ratio = cur/tot;
889                     est = (zint)(0.5+zebraSet->hits/ratio);
890                     yaz_log(log_level_searchhits, "Estimating hits (%s) "
891                                   "%0.1f->" ZINT_FORMAT
892                                   "; %0.1f->" ZINT_FORMAT,
893                                   rset->control->desc,
894                                   cur, zebraSet->hits,
895                                   tot, est);
896                     i = 0; /* round to 3 significant digits */
897                     while (est>1000) {
898                         est /= 10;
899                         i++;
900                     }
901                     while (i--)
902                         est *= 10;
903                     zebraSet->hits = est;
904                 }
905             }
906         }
907         while (rset_read (rfd, &key,&termid) && (est<0) );
908         score = (*rc->calc)(handle, psysno);
909         resultSetInsertRank(zh, sort_info, psysno, score, 'A');
910         (*rc->end) (zh->reg, handle);
911     }
912     rset_close (rfd);
913
914     yaz_log(log_level_searchterms, ZINT_FORMAT " keys, " ZINT_FORMAT " sysnos, rank",
915             kno, zebraSet->hits);
916     for (i = 0; i < numTerms; i++)
917     {
918         yaz_log(log_level_searchterms, "term=\"%s\" type=%s count=" ZINT_FORMAT,
919                  terms[i]->name, terms[i]->flags, rset_count(terms[i]->rset));
920     }
921 }
922
923 ZebraRankClass zebraRankLookup (ZebraHandle zh, const char *name)
924 {
925     ZebraRankClass p = zh->reg->rank_classes;
926     while (p && strcmp (p->control->name, name))
927         p = p->next;
928     if (p && !p->init_flag)
929     {
930         if (p->control->create)
931             p->class_handle = (*p->control->create)(zh);
932         p->init_flag = 1;
933     }
934     return p;
935 }
936
937 void zebraRankInstall (struct zebra_register *reg, struct rank_control *ctrl)
938 {
939     ZebraRankClass p = (ZebraRankClass) xmalloc (sizeof(*p));
940     p->control = (struct rank_control *) xmalloc (sizeof(*p->control));
941     memcpy (p->control, ctrl, sizeof(*p->control));
942     p->control->name = xstrdup (ctrl->name);
943     p->init_flag = 0;
944     p->next = reg->rank_classes;
945     reg->rank_classes = p;
946 }
947
948 void zebraRankDestroy (struct zebra_register *reg)
949 {
950     ZebraRankClass p = reg->rank_classes;
951     while (p)
952     {
953         ZebraRankClass p_next = p->next;
954         if (p->init_flag && p->control->destroy)
955             (*p->control->destroy)(reg, p->class_handle);
956         xfree(p->control->name);
957         xfree(p->control);
958         xfree(p);
959         p = p_next;
960     }
961     reg->rank_classes = NULL;
962 }