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