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