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