using a few more zints for hitcounts etc
[idzebra-moved-to-github.git] / index / zsets.c
1 /* $Id: zsets.c,v 1.55 2004-08-10 08:19:15 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
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
191 ZebraSet resultSetAdd (ZebraHandle zh, const char *name, int ov)
192 {
193     ZebraSet s;
194     int i;
195
196     for (s = zh->sets; s; s = s->next)
197         if (!strcmp (s->name, name))
198             break;
199     if (s)
200     {
201         yaz_log (LOG_DEBUG, "updating result set %s", name);
202         if (!ov || s->locked)
203             return NULL;
204         if (s->rset)
205             rset_delete (s->rset);
206         if (s->nmem)
207             nmem_destroy (s->nmem);
208     }
209     else
210     {
211         const char *sort_max_str = zebra_get_resource(zh, "sortmax", "1000");
212
213         yaz_log (LOG_DEBUG, "adding result set %s", name);
214         s = (ZebraSet) xmalloc (sizeof(*s));
215         s->next = zh->sets;
216         zh->sets = s;
217         s->name = (char *) xmalloc (strlen(name)+1);
218         strcpy (s->name, name);
219
220         s->sort_info = (struct zset_sort_info *)
221             xmalloc (sizeof(*s->sort_info));
222         s->sort_info->max_entries = atoi(sort_max_str);
223         if (s->sort_info->max_entries < 2)
224             s->sort_info->max_entries = 2;
225
226         s->sort_info->entries = (struct zset_sort_entry **)
227             xmalloc (sizeof(*s->sort_info->entries) *
228                      s->sort_info->max_entries);
229         s->sort_info->all_entries = (struct zset_sort_entry *)
230             xmalloc (sizeof(*s->sort_info->all_entries) *
231                      s->sort_info->max_entries);
232         for (i = 0; i < s->sort_info->max_entries; i++)
233             s->sort_info->entries[i] = s->sort_info->all_entries + i;
234     }
235     s->locked = 0;
236     s->term_entries = 0;
237     s->hits = 0;
238     s->rset = 0;
239     s->nmem = 0;
240     s->rpn = 0;
241     return s;
242 }
243
244 ZebraSet resultSetGet (ZebraHandle zh, const char *name)
245 {
246     ZebraSet s;
247
248     for (s = zh->sets; s; s = s->next)
249         if (!strcmp (s->name, name))
250         {
251             if (!s->term_entries && !s->rset && s->rpn)
252             {
253                 NMEM nmem = nmem_create ();
254                 yaz_log (LOG_LOG, "research %s", name);
255                 s->rset =
256                     rpn_search (zh, nmem, s->rpn, s->num_bases,
257                                 s->basenames, s->name, s);
258                 nmem_destroy (nmem);
259             }
260             return s;
261         }
262     return NULL;
263 }
264
265 void resultSetInvalidate (ZebraHandle zh)
266 {
267     ZebraSet s = zh->sets;
268     
269     for (; s; s = s->next)
270     {
271         if (s->rset)
272             rset_delete (s->rset);
273         s->rset = 0;
274     }
275 }
276
277 void resultSetDestroy (ZebraHandle zh, int num, char **names,int *statuses)
278 {
279     ZebraSet * ss = &zh->sets;
280     int i;
281     
282     if (statuses)
283         for (i = 0; i<num; i++)
284             statuses[i] = Z_DeleteStatus_resultSetDidNotExist;
285     zh->errCode = 0;
286     zh->errString = NULL;
287     while (*ss)
288     {
289         int i = -1;
290         ZebraSet s = *ss;
291         if (num >= 0)
292         {
293             for (i = 0; i<num; i++)
294                 if (!strcmp (s->name, names[i]))
295                 {
296                     if (statuses)
297                         statuses[i] = Z_DeleteStatus_success;
298                     i = -1;
299                     break;
300                 }
301         }
302         if (i < 0)
303         {
304             *ss = s->next;
305             
306             xfree (s->sort_info->all_entries);
307             xfree (s->sort_info->entries);
308             xfree (s->sort_info);
309             
310             if (s->nmem)
311                 nmem_destroy (s->nmem);
312             if (s->rset)
313                 rset_delete (s->rset);
314             xfree (s->name);
315             xfree (s);
316         }
317         else
318             ss = &s->next;
319     }
320 }
321
322 ZebraPosSet zebraPosSetCreate (ZebraHandle zh, const char *name, 
323                                int num, int *positions)
324 {
325     ZebraSet sset;
326     ZebraPosSet sr = 0;
327     RSET rset;
328     int i;
329     struct zset_sort_info *sort_info;
330
331     if (!(sset = resultSetGet (zh, name)))
332         return NULL;
333     if (!(rset = sset->rset))
334     {
335         if (!sset->term_entries)
336             return 0;
337         sr = (ZebraPosSet) xmalloc (sizeof(*sr) * num);
338         for (i = 0; i<num; i++)
339         {
340             sr[i].sysno = 0;
341             sr[i].score = -1;
342             sr[i].term = 0;
343             sr[i].db = 0;
344
345             if (positions[i] <= sset->term_entries_max)
346             {
347                 sr[i].term = sset->term_entries[positions[i]-1].term;
348                 sr[i].db = sset->term_entries[positions[i]-1].db;
349             }
350         }
351     }
352     else
353     {
354         sr = (ZebraPosSet) xmalloc (sizeof(*sr) * num);
355         for (i = 0; i<num; i++)
356         {
357             sr[i].sysno = 0;
358             sr[i].score = -1;
359             sr[i].term = 0;
360             sr[i].db = 0;
361         }
362         sort_info = sset->sort_info;
363         if (sort_info)
364         {
365             int position;
366             
367             for (i = 0; i<num; i++)
368             {
369                 position = positions[i];
370                 if (position > 0 && position <= sort_info->num_entries)
371                 {
372                     yaz_log (LOG_DEBUG, "got pos=%d (sorted)", position);
373                     sr[i].sysno = sort_info->entries[position-1]->sysno;
374                     sr[i].score = sort_info->entries[position-1]->score;
375                 }
376             }
377         }
378         /* did we really get all entries using sort ? */
379         for (i = 0; i<num; i++)
380         {
381             if (!sr[i].sysno)
382                 break;
383         }
384         if (i < num) /* nope, get the rest, unsorted - sorry */
385         {
386             int position = 0;
387             int num_i = 0;
388             zint psysno = 0;
389             int term_index;
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, &term_index))
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     int term_index;
620     RSFD rfd;
621
622     yaz_log (LOG_LOG, "resultSetSortSingle start");
623     assert(nmem); /* compiler shut up about unused param */
624     sset->sort_info->num_entries = 0;
625
626     sset->hits = 0;
627     num_criteria = sort_sequence->num_specs;
628     if (num_criteria > 3)
629         num_criteria = 3;
630     for (i = 0; i < num_criteria; i++)
631     {
632         Z_SortKeySpec *sks = sort_sequence->specs[i];
633         Z_SortKey *sk;
634
635         if (*sks->sortRelation == Z_SortKeySpec_ascending)
636             sort_criteria[i].relation = 'A';
637         else if (*sks->sortRelation == Z_SortKeySpec_descending)
638             sort_criteria[i].relation = 'D';
639         else
640         {
641             zh->errCode = 214;
642             return;
643         }
644         if (sks->sortElement->which == Z_SortElement_databaseSpecific)
645         {
646             zh->errCode = 210;
647             return;
648         }
649         else if (sks->sortElement->which != Z_SortElement_generic)
650         {
651             zh->errCode = 237;
652             return;
653         }       
654         sk = sks->sortElement->u.generic;
655         switch (sk->which)
656         {
657         case Z_SortKey_sortField:
658             yaz_log (LOG_DEBUG, "Sort: key %d is of type sortField", i+1);
659             zh->errCode = 207;
660             return;
661         case Z_SortKey_elementSpec:
662             yaz_log (LOG_DEBUG, "Sort: key %d is of type elementSpec", i+1);
663             zh->errCode = 207;
664             return;
665         case Z_SortKey_sortAttributes:
666             yaz_log (LOG_DEBUG, "Sort: key %d is of type sortAttributes", i+1);
667             sort_criteria[i].attrUse =
668                 zebra_maps_sort (zh->reg->zebra_maps,
669                                  sk->u.sortAttributes,
670                                  &sort_criteria[i].numerical);
671             yaz_log (LOG_DEBUG, "use value = %d", sort_criteria[i].attrUse);
672             if (sort_criteria[i].attrUse == -1)
673             {
674                 zh->errCode = 116;
675                 return;
676             }
677             if (sortIdx_type (zh->reg->sortIdx, sort_criteria[i].attrUse))
678             {
679                 zh->errCode = 207;
680                 return;
681             }
682             break;
683         }
684     }
685     rfd = rset_open (rset, RSETF_READ);
686     while (rset_read (rset, rfd, &key, &term_index))
687     {
688 #if IT_KEY_NEW
689         zint this_sys = key.mem[0];
690 #else
691         zint this_sys = key.sysno;
692 #endif
693         if (this_sys != psysno)
694         {
695             (sset->hits)++;
696             psysno = this_sys;
697             resultSetInsertSort (zh, sset,
698                                  sort_criteria, num_criteria, psysno);
699         }
700     }
701     rset_close (rset, rfd);
702
703     for (i = 0; i < rset->no_rset_terms; i++)
704         yaz_log (LOG_LOG, "term=\"%s\" nn=" ZINT_FORMAT " type=%s count=" ZINT_FORMAT,
705                  rset->rset_terms[i]->name,
706                  rset->rset_terms[i]->nn,
707                  rset->rset_terms[i]->flags,
708                  rset->rset_terms[i]->count);
709
710     *sort_status = Z_SortResponse_success;
711     yaz_log (LOG_LOG, "resultSetSortSingle end");
712 }
713
714 RSET resultSetRef (ZebraHandle zh, const char *resultSetId)
715 {
716     ZebraSet s;
717
718     if ((s = resultSetGet (zh, resultSetId)))
719         return s->rset;
720     return NULL;
721 }
722
723 void resultSetRank (ZebraHandle zh, ZebraSet zebraSet, RSET rset)
724 {
725     zint kno = 0;
726     struct it_key key;
727     RSFD rfd;
728     int term_index, i;
729     ZebraRankClass rank_class;
730     struct rank_control *rc;
731     struct zset_sort_info *sort_info;
732     const char *rank_handler_name = res_get_def(zh->res, "rank", "rank-1");
733     double cur,tot; 
734     zint est=-2; /* -2 not done, -1 can't do, >0 actual estimate*/
735     zint esthits;
736
737     sort_info = zebraSet->sort_info;
738     sort_info->num_entries = 0;
739     zebraSet->hits = 0;
740     rfd = rset_open (rset, RSETF_READ);
741
742     yaz_log (LOG_LOG, "resultSetRank");
743
744     rank_class = zebraRankLookup (zh, rank_handler_name);
745     if (!rank_class)
746     {
747         yaz_log (LOG_WARN, "No such rank handler: %s", rank_handler_name);
748         return;
749     }
750     rc = rank_class->control;
751
752     if (rset_read (rset, rfd, &key, &term_index))
753     {
754 #if IT_KEY_NEW
755         zint psysno = key.mem[0];
756 #else
757         zint psysno = key.sysno;
758 #endif
759         int score;
760         void *handle =
761             (*rc->begin) (zh->reg, rank_class->class_handle, rset);
762         (zebraSet->hits)++;
763     esthits=atoi(res_get_def(zh->res,"estimatehits","0"));
764     if (!esthits) est=-1; /* can not do */
765         do
766         {
767 #if IT_KEY_NEW
768             zint this_sys = key.mem[0];
769 #else
770             zint this_sys = key.sysno;
771 #endif
772             kno++;
773             if (this_sys != psysno)
774             {
775                 score = (*rc->calc) (handle, psysno);
776
777                 resultSetInsertRank (zh, sort_info, psysno, score, 'A');
778                 (zebraSet->hits)++;
779                 psysno = this_sys;
780             }
781             (*rc->add) (handle, this_sys, term_index);
782         if ( (est==-2) && (zebraSet->hits==esthits))
783         { /* time to estimate the hits */
784             double f;
785             rset_pos(rset,rfd,&cur,&tot); 
786             if (tot>0) {
787                 f=cur/tot;
788                 est=(zint)(0.5+zebraSet->hits/f);
789                 logf(LOG_LOG, "Estimating hits (%s) "
790                               "%0.1f->"ZINT_FORMAT
791                               "; %0.1f->"ZINT_FORMAT,
792                               rset->control->desc,
793                               cur, zebraSet->hits,
794                               tot,est);
795                 i=0; /* round to 3 significant digits */
796                 while (est>1000) {
797                     est/=10;
798                     i++;
799                 }
800                 while (i--) est*=10;
801                 zebraSet->hits=est;
802             }
803         }
804         }
805         while (rset_read (rset, rfd, &key, &term_index) && (est<0) );
806            
807         score = (*rc->calc) (handle, psysno);
808         resultSetInsertRank (zh, sort_info, psysno, score, 'A');
809         (*rc->end) (zh->reg, handle);
810     }
811     rset_close (rset, rfd);
812
813     for (i = 0; i < rset->no_rset_terms; i++)
814         yaz_log (LOG_LOG, "term=\"%s\" nn=" ZINT_FORMAT " type=%s count=" ZINT_FORMAT,
815                  rset->rset_terms[i]->name,
816                  rset->rset_terms[i]->nn,
817                  rset->rset_terms[i]->flags,
818                  rset->rset_terms[i]->count);
819     
820     yaz_log (LOG_LOG, ZINT_FORMAT " keys, "ZINT_FORMAT" distinct sysnos", 
821                     kno, zebraSet->hits);
822 }
823
824 ZebraRankClass zebraRankLookup (ZebraHandle zh, const char *name)
825 {
826     ZebraRankClass p = zh->reg->rank_classes;
827     while (p && strcmp (p->control->name, name))
828         p = p->next;
829     if (p && !p->init_flag)
830     {
831         if (p->control->create)
832             p->class_handle = (*p->control->create)(zh);
833         p->init_flag = 1;
834     }
835     return p;
836 }
837
838 void zebraRankInstall (struct zebra_register *reg, struct rank_control *ctrl)
839 {
840     ZebraRankClass p = (ZebraRankClass) xmalloc (sizeof(*p));
841     p->control = (struct rank_control *) xmalloc (sizeof(*p->control));
842     memcpy (p->control, ctrl, sizeof(*p->control));
843     p->control->name = xstrdup (ctrl->name);
844     p->init_flag = 0;
845     p->next = reg->rank_classes;
846     reg->rank_classes = p;
847 }
848
849 void zebraRankDestroy (struct zebra_register *reg)
850 {
851     ZebraRankClass p = reg->rank_classes;
852     while (p)
853     {
854         ZebraRankClass p_next = p->next;
855         if (p->init_flag && p->control->destroy)
856             (*p->control->destroy)(reg, p->class_handle);
857         xfree (p->control->name);
858         xfree (p->control);
859         xfree (p);
860         p = p_next;
861     }
862     reg->rank_classes = NULL;
863 }