Using a separate nmem for creating rsets
[idzebra-moved-to-github.git] / index / zsets.c
1 /* $Id: zsets.c,v 1.58 2004-08-30 12:32:24 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     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 (rset, rfd, &key))
407             {
408 #if IT_KEY_NEW
409                 zint this_sys = key.mem[0];
410 #else
411                 zint this_sys = key.sysno;
412 #endif
413                 if (this_sys != psysno)
414                 {
415                     psysno = this_sys;
416                     if (sort_info)
417                     {
418                         /* determine we alreay have this in our set */
419                         for (i = sort_info->num_entries; --i >= 0; )
420                             if (psysno == sort_info->entries[i]->sysno)
421                                 break;
422                         if (i >= 0)
423                             continue;
424                     }
425                     position++;
426                     assert (num_i < num);
427                     if (position == positions[num_i])
428                     {
429                         sr[num_i].sysno = psysno;
430                         yaz_log (LOG_DEBUG, "got pos=%d (unsorted)", position);
431                         sr[num_i].score = -1;
432                         num_i++;
433                     }
434                 }
435             }
436             rset_close (rset, rfd);
437         }
438     }
439     return sr;
440 }
441
442 void zebraPosSetDestroy (ZebraHandle zh, ZebraPosSet records, int num)
443 {
444     assert(zh); /* compiler shut up about unused arg */
445     xfree (records);
446 }
447
448 struct sortKeyInfo {
449     int relation;
450     int attrUse;
451     int numerical;
452 };
453
454 void resultSetInsertSort (ZebraHandle zh, ZebraSet sset,
455                           struct sortKeyInfo *criteria, int num_criteria,
456                           zint sysno)
457 {
458     struct zset_sort_entry this_entry;
459     struct zset_sort_entry *new_entry = NULL;
460     struct zset_sort_info *sort_info = sset->sort_info;
461     int i, j;
462
463     sortIdx_sysno (zh->reg->sortIdx, sysno);
464     for (i = 0; i<num_criteria; i++)
465     {
466         sortIdx_type (zh->reg->sortIdx, criteria[i].attrUse);
467         sortIdx_read (zh->reg->sortIdx, this_entry.buf[i]);
468     }
469     i = sort_info->num_entries;
470     while (--i >= 0)
471     {
472         int rel = 0;
473         for (j = 0; j<num_criteria; j++)
474         {
475             if (criteria[j].numerical)
476             {
477                 double diff = atof(this_entry.buf[j]) -
478                               atof(sort_info->entries[i]->buf[j]);
479                 rel = 0;
480                 if (diff > 0.0)
481                     rel = 1;
482                 else if (diff < 0.0)
483                     rel = -1;
484             }
485             else
486             {
487                 rel = memcmp (this_entry.buf[j], sort_info->entries[i]->buf[j],
488                           SORT_IDX_ENTRYSIZE);
489             }
490             if (rel)
491                 break;
492         }       
493         if (!rel)
494             break;
495         if (criteria[j].relation == 'A')
496         {
497             if (rel > 0)
498                 break;
499         }
500         else if (criteria[j].relation == 'D')
501         {
502             if (rel < 0)
503                 break;
504         }
505     }
506     ++i;
507     j = sort_info->max_entries;
508     if (i == j)
509         return;
510
511     if (sort_info->num_entries == j)
512         --j;
513     else
514         j = (sort_info->num_entries)++;
515     new_entry = sort_info->entries[j];
516     while (j != i)
517     {
518         sort_info->entries[j] = sort_info->entries[j-1];
519         --j;
520     }
521     sort_info->entries[i] = new_entry;
522     assert (new_entry);
523     for (i = 0; i<num_criteria; i++)
524         memcpy (new_entry->buf[i], this_entry.buf[i], SORT_IDX_ENTRYSIZE);
525     new_entry->sysno = sysno;
526     new_entry->score = -1;
527 }
528
529 void resultSetInsertRank (ZebraHandle zh, struct zset_sort_info *sort_info,
530                           zint sysno, int score, int relation)
531 {
532     struct zset_sort_entry *new_entry = NULL;
533     int i, j;
534     assert(zh); /* compiler shut up about unused arg */
535
536     i = sort_info->num_entries;
537     while (--i >= 0)
538     {
539         int rel = 0;
540
541         rel = score - sort_info->entries[i]->score;
542
543         if (relation == 'D')
544         {
545             if (rel >= 0)
546                 break;
547         }
548         else if (relation == 'A')
549         {
550             if (rel <= 0)
551                 break;
552         }
553     }
554     ++i;
555     j = sort_info->max_entries;
556     if (i == j)
557         return;
558
559     if (sort_info->num_entries == j)
560         --j;
561     else
562         j = (sort_info->num_entries)++;
563     
564     new_entry = sort_info->entries[j];
565     while (j != i)
566     {
567         sort_info->entries[j] = sort_info->entries[j-1];
568         --j;
569     }
570     sort_info->entries[i] = new_entry;
571     assert (new_entry);
572     new_entry->sysno = sysno;
573     new_entry->score = score;
574 }
575
576 void resultSetSort (ZebraHandle zh, NMEM nmem,
577                     int num_input_setnames, const char **input_setnames,
578                     const char *output_setname,
579                     Z_SortKeySpecList *sort_sequence, int *sort_status)
580 {
581     ZebraSet sset;
582     RSET rset;
583
584     if (num_input_setnames == 0)
585     {
586         zh->errCode = 208;
587         return ;
588     }
589     if (num_input_setnames > 1)
590     {
591         zh->errCode = 230;
592         return;
593     }
594     yaz_log (LOG_DEBUG, "result set sort input=%s output=%s",
595           *input_setnames, output_setname);
596     sset = resultSetGet (zh, input_setnames[0]);
597     if (!sset)
598     {
599         zh->errCode = 30;
600         zh->errString = nmem_strdup (nmem, input_setnames[0]);
601         return;
602     }
603     if (!(rset = sset->rset))
604     {
605         zh->errCode = 30;
606         zh->errString = nmem_strdup (nmem, input_setnames[0]);
607         return;
608     }
609     if (strcmp (output_setname, input_setnames[0]))
610     {
611         rset = rset_dup (rset);
612         sset = resultSetAdd (zh, output_setname, 1);
613         sset->rset = rset;
614     }
615     resultSetSortSingle (zh, nmem, sset, rset, sort_sequence, sort_status);
616 }
617
618 void resultSetSortSingle (ZebraHandle zh, NMEM nmem,
619                           ZebraSet sset, RSET rset,
620                           Z_SortKeySpecList *sort_sequence, int *sort_status)
621 {
622     int i;
623     zint psysno = 0;
624     struct it_key key;
625     struct sortKeyInfo sort_criteria[3];
626     int num_criteria;
627     RSFD rfd;
628
629     yaz_log (LOG_LOG, "resultSetSortSingle start");
630     assert(nmem); /* compiler shut up about unused param */
631     sset->sort_info->num_entries = 0;
632
633     sset->hits = 0;
634     num_criteria = sort_sequence->num_specs;
635     if (num_criteria > 3)
636         num_criteria = 3;
637     for (i = 0; i < num_criteria; i++)
638     {
639         Z_SortKeySpec *sks = sort_sequence->specs[i];
640         Z_SortKey *sk;
641
642         if (*sks->sortRelation == Z_SortKeySpec_ascending)
643             sort_criteria[i].relation = 'A';
644         else if (*sks->sortRelation == Z_SortKeySpec_descending)
645             sort_criteria[i].relation = 'D';
646         else
647         {
648             zh->errCode = 214;
649             return;
650         }
651         if (sks->sortElement->which == Z_SortElement_databaseSpecific)
652         {
653             zh->errCode = 210;
654             return;
655         }
656         else if (sks->sortElement->which != Z_SortElement_generic)
657         {
658             zh->errCode = 237;
659             return;
660         }       
661         sk = sks->sortElement->u.generic;
662         switch (sk->which)
663         {
664         case Z_SortKey_sortField:
665             yaz_log (LOG_DEBUG, "Sort: key %d is of type sortField", i+1);
666             zh->errCode = 207;
667             return;
668         case Z_SortKey_elementSpec:
669             yaz_log (LOG_DEBUG, "Sort: key %d is of type elementSpec", i+1);
670             zh->errCode = 207;
671             return;
672         case Z_SortKey_sortAttributes:
673             yaz_log (LOG_DEBUG, "Sort: key %d is of type sortAttributes", i+1);
674             sort_criteria[i].attrUse =
675                 zebra_maps_sort (zh->reg->zebra_maps,
676                                  sk->u.sortAttributes,
677                                  &sort_criteria[i].numerical);
678             yaz_log (LOG_DEBUG, "use value = %d", sort_criteria[i].attrUse);
679             if (sort_criteria[i].attrUse == -1)
680             {
681                 zh->errCode = 116;
682                 return;
683             }
684             if (sortIdx_type (zh->reg->sortIdx, sort_criteria[i].attrUse))
685             {
686                 zh->errCode = 207;
687                 return;
688             }
689             break;
690         }
691     }
692     rfd = rset_open (rset, RSETF_READ);
693     while (rset_read (rset, rfd, &key))
694     {
695 #if IT_KEY_NEW
696         zint this_sys = key.mem[0];
697 #else
698         zint this_sys = key.sysno;
699 #endif
700         if (this_sys != psysno)
701         {
702             (sset->hits)++;
703             psysno = this_sys;
704             resultSetInsertSort (zh, sset,
705                                  sort_criteria, num_criteria, psysno);
706         }
707     }
708     rset_close (rset, rfd);
709    
710 #if 0
711     for (i = 0; i < rset->no_rset_terms; i++)
712         yaz_log (LOG_LOG, "term=\"%s\" nn=" ZINT_FORMAT 
713                           " type=%s count=" ZINT_FORMAT,
714                  rset->rset_terms[i]->name,
715                  rset->rset_terms[i]->nn,
716                  rset->rset_terms[i]->flags,
717                  rset->rset_terms[i]->count);
718 #endif
719     *sort_status = Z_SortResponse_success;
720     yaz_log (LOG_LOG, "resultSetSortSingle end");
721 }
722
723 RSET resultSetRef (ZebraHandle zh, const char *resultSetId)
724 {
725     ZebraSet s;
726
727     if ((s = resultSetGet (zh, resultSetId)))
728         return s->rset;
729     return NULL;
730 }
731
732 void resultSetRank (ZebraHandle zh, ZebraSet zebraSet, RSET rset)
733 {
734     zint kno = 0;
735     struct it_key key;
736     RSFD rfd;
737     /* int term_index; */
738     int i;
739     ZebraRankClass rank_class;
740     struct rank_control *rc;
741     struct zset_sort_info *sort_info;
742     const char *rank_handler_name = res_get_def(zh->res, "rank", "rank-1");
743     double cur,tot; 
744     zint est=-2; /* -2 not done, -1 can't do, >0 actual estimate*/
745     zint esthits;
746     double ratio;
747
748     sort_info = zebraSet->sort_info;
749     sort_info->num_entries = 0;
750     zebraSet->hits = 0;
751     rfd = rset_open (rset, RSETF_READ);
752
753     yaz_log (LOG_LOG, "resultSetRank");
754
755     rank_class = zebraRankLookup (zh, rank_handler_name);
756     if (!rank_class)
757     {
758         yaz_log (LOG_WARN, "No such rank handler: %s", rank_handler_name);
759         return;
760     }
761     rc = rank_class->control;
762
763     if (rset_read (rset, rfd, &key))
764     {
765 #if IT_KEY_NEW
766         zint psysno = key.mem[0];
767 #else
768         zint psysno = key.sysno;
769 #endif
770         int score;
771         void *handle =
772             (*rc->begin) (zh->reg, rank_class->class_handle, rset);
773         (zebraSet->hits)++;
774         esthits=atoi(res_get_def(zh->res,"estimatehits","0"));
775         if (!esthits) 
776             est=-1; /* can not do */
777         do
778         {
779 #if IT_KEY_NEW
780             zint this_sys = key.mem[0];
781 #else
782             zint this_sys = key.sysno;
783 #endif
784             kno++;
785             if (this_sys != psysno)
786             {
787                 score = (*rc->calc) (handle, psysno);
788
789                 resultSetInsertRank (zh, sort_info, psysno, score, 'A');
790                 (zebraSet->hits)++;
791                 psysno = this_sys;
792             }
793             /* FIXME - Ranking is broken, since rsets no longer have */
794             /* term lists! */
795             /* (*rc->add) (handle, this_sys, term_index); */
796             
797         if ( (est==-2) && (zebraSet->hits==esthits))
798         { /* time to estimate the hits */
799             rset_pos(rset,rfd,&cur,&tot); 
800             if (tot>0) {
801                 ratio=cur/tot;
802                 est=(zint)(0.5+zebraSet->hits/ratio);
803                 logf(LOG_LOG, "Estimating hits (%s) "
804                               "%0.1f->"ZINT_FORMAT
805                               "; %0.1f->"ZINT_FORMAT,
806                               rset->control->desc,
807                               cur, zebraSet->hits,
808                               tot,est);
809                 i=0; /* round to 3 significant digits */
810                 while (est>1000) {
811                     est/=10;
812                     i++;
813                 }
814                 while (i--) est*=10;
815                 zebraSet->hits=est;
816             }
817         }
818         }
819         while (rset_read (rset, rfd, &key) && (est<0) );
820            
821         score = (*rc->calc) (handle, psysno);
822         resultSetInsertRank (zh, sort_info, psysno, score, 'A');
823         (*rc->end) (zh->reg, handle);
824     }
825     rset_close (rset, rfd);
826 /*
827     for (i = 0; i < rset->no_rset_terms; i++)
828     {
829         if (est>0)
830             rset->rset_terms[i]->count = 
831                 est=(zint)(rset->rset_terms[i]->count/ratio);
832         yaz_log (LOG_LOG, "term=\"%s\" nn=" ZINT_FORMAT 
833                     " type=%s count=" ZINT_FORMAT,
834                  rset->rset_terms[i]->name,
835                  rset->rset_terms[i]->nn,
836                  rset->rset_terms[i]->flags,
837                  rset->rset_terms[i]->count);
838     }
839 */
840     yaz_log (LOG_LOG, ZINT_FORMAT " keys, "ZINT_FORMAT" distinct sysnos", 
841                     kno, zebraSet->hits);
842 }
843
844 ZebraRankClass zebraRankLookup (ZebraHandle zh, const char *name)
845 {
846     ZebraRankClass p = zh->reg->rank_classes;
847     while (p && strcmp (p->control->name, name))
848         p = p->next;
849     if (p && !p->init_flag)
850     {
851         if (p->control->create)
852             p->class_handle = (*p->control->create)(zh);
853         p->init_flag = 1;
854     }
855     return p;
856 }
857
858 void zebraRankInstall (struct zebra_register *reg, struct rank_control *ctrl)
859 {
860     ZebraRankClass p = (ZebraRankClass) xmalloc (sizeof(*p));
861     p->control = (struct rank_control *) xmalloc (sizeof(*p->control));
862     memcpy (p->control, ctrl, sizeof(*p->control));
863     p->control->name = xstrdup (ctrl->name);
864     p->init_flag = 0;
865     p->next = reg->rank_classes;
866     reg->rank_classes = p;
867 }
868
869 void zebraRankDestroy (struct zebra_register *reg)
870 {
871     ZebraRankClass p = reg->rank_classes;
872     while (p)
873     {
874         ZebraRankClass p_next = p->next;
875         if (p->init_flag && p->control->destroy)
876             (*p->control->destroy)(reg, p->class_handle);
877         xfree (p->control->name);
878         xfree (p->control);
879         xfree (p);
880         p = p_next;
881     }
882     reg->rank_classes = NULL;
883 }