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