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