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