Fixed bug #245: Time for getting records changes a lot based on record
[idzebra-moved-to-github.git] / index / zsets.c
1 /* $Id: zsets.c,v 1.49.2.2 2005-01-07 14:06:16 adam 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     int hits;
50     int num_bases;
51     char **basenames;
52     Z_RPNQuery *rpn;
53     struct zset_sort_info *sort_info;
54     struct zebra_set_term_entry *term_entries;
55     int term_entries_max;
56     struct zebra_set *next;
57     int locked;
58
59     int cache_position;  /* last position */
60     RSFD cache_rfd;      /* rfd (NULL if not existing) */
61     int cache_psysno;
62 };
63
64 struct zset_sort_entry {
65     int sysno;
66     int score;
67     char buf[ZSET_SORT_MAX_LEVEL][SORT_IDX_ENTRYSIZE];
68 };
69
70 struct zset_sort_info {
71     int max_entries;
72     int num_entries;
73     struct zset_sort_entry *all_entries;
74     struct zset_sort_entry **entries;
75 };
76
77 ZebraSet resultSetAddRPN (ZebraHandle zh, NMEM m,
78                           Z_RPNQuery *rpn, int num_bases,
79                           char **basenames, 
80                           const char *setname)
81 {
82     ZebraSet zebraSet;
83     int i;
84
85     zh->errCode = 0;
86     zh->errString = NULL;
87     zh->hits = 0;
88
89     zebraSet = resultSetAdd (zh, setname, 1);
90     if (!zebraSet)
91         return 0;
92     zebraSet->locked = 1;
93     zebraSet->rpn = 0;
94     zebraSet->nmem = m;
95     
96     zebraSet->num_bases = num_bases;
97     zebraSet->basenames = 
98         nmem_malloc (zebraSet->nmem, num_bases * sizeof(*zebraSet->basenames));
99     for (i = 0; i<num_bases; i++)
100         zebraSet->basenames[i] = nmem_strdup (zebraSet->nmem, basenames[i]);
101
102
103     zebraSet->rset = rpn_search (zh, zebraSet->nmem, rpn,
104                                  zebraSet->num_bases,
105                                  zebraSet->basenames, zebraSet->name,
106                                  zebraSet);
107     zh->hits = zebraSet->hits;
108     if (zebraSet->rset)
109         zebraSet->rpn = rpn;
110     zebraSet->locked = 0;
111     return zebraSet;
112 }
113
114 void resultSetAddTerm (ZebraHandle zh, ZebraSet s, int reg_type,
115                        const char *db, int set,
116                        int use, const char *term)
117 {
118     if (!s->nmem)
119         s->nmem = nmem_create ();
120     if (!s->term_entries)
121     {
122         int i;
123         s->term_entries_max = 1000;
124         s->term_entries =
125             nmem_malloc (s->nmem, s->term_entries_max * 
126                          sizeof(*s->term_entries));
127         for (i = 0; i < s->term_entries_max; i++)
128             s->term_entries[i].term = 0;
129     }
130     if (s->hits < s->term_entries_max)
131     {
132         s->term_entries[s->hits].reg_type = reg_type;
133         s->term_entries[s->hits].db = nmem_strdup (s->nmem, db);
134         s->term_entries[s->hits].set = set;
135         s->term_entries[s->hits].use = use;
136         s->term_entries[s->hits].term = nmem_strdup (s->nmem, term);
137     }
138     (s->hits)++;
139 }
140
141
142 int zebra_resultSetTerms (ZebraHandle zh, const char *setname, 
143                           int no, int *count, 
144                           int *type, char *out, size_t *len)
145 {
146     ZebraSet s = resultSetGet (zh, setname);
147     int no_max = 0;
148
149     if (count)
150         *count = 0;
151     if (!s || !s->rset)
152         return 0;
153     no_max = s->rset->no_rset_terms;
154     if (no < 0 || no >= no_max)
155         return 0;
156     if (count)
157         *count = s->rset->rset_terms[no]->count;
158     if (type)
159         *type = s->rset->rset_terms[no]->type;
160     
161     if (out)
162     {
163         char *inbuf = s->rset->rset_terms[no]->name;
164         size_t inleft = strlen(inbuf);
165         size_t outleft = *len - 1;
166         int converted = 0;
167
168         if (zh->iconv_from_utf8 != 0)
169         {
170             char *outbuf = out;
171             size_t ret;
172             
173             ret = yaz_iconv(zh->iconv_from_utf8, &inbuf, &inleft,
174                         &outbuf, &outleft);
175             if (ret == (size_t)(-1))
176                 *len = 0;
177             else
178                 *len = outbuf - out;
179             converted = 1;
180         }
181         if (!converted)
182         {
183             if (inleft > outleft)
184                 inleft = outleft;
185             *len = inleft;
186             memcpy (out, inbuf, *len);
187         }
188         out[*len] = 0;
189     }
190     return no_max;
191 }
192
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         {
209             if (s->cache_rfd)
210                 rset_close(s->rset, s->cache_rfd);
211             rset_delete (s->rset);
212         }
213         if (s->nmem)
214             nmem_destroy (s->nmem);
215     }
216     else
217     {
218         const char *sort_max_str = zebra_get_resource(zh, "sortmax", "2");
219
220         yaz_log (LOG_DEBUG, "adding result set %s", name);
221         s = (ZebraSet) xmalloc (sizeof(*s));
222         s->next = zh->sets;
223         zh->sets = s;
224         s->name = (char *) xmalloc (strlen(name)+1);
225         strcpy (s->name, name);
226
227         s->sort_info = (struct zset_sort_info *)
228             xmalloc (sizeof(*s->sort_info));
229         s->sort_info->max_entries = atoi(sort_max_str);
230         if (s->sort_info->max_entries < 2)
231             s->sort_info->max_entries = 2;
232
233         s->sort_info->entries = (struct zset_sort_entry **)
234             xmalloc (sizeof(*s->sort_info->entries) *
235                      s->sort_info->max_entries);
236         s->sort_info->all_entries = (struct zset_sort_entry *)
237             xmalloc (sizeof(*s->sort_info->all_entries) *
238                      s->sort_info->max_entries);
239         for (i = 0; i < s->sort_info->max_entries; i++)
240             s->sort_info->entries[i] = s->sort_info->all_entries + i;
241     }
242     s->locked = 0;
243     s->term_entries = 0;
244     s->hits = 0;
245     s->rset = 0;
246     s->nmem = 0;
247     s->rpn = 0;
248     s->cache_position = 0;
249     s->cache_rfd = 0;
250     return s;
251 }
252
253 ZebraSet resultSetGet (ZebraHandle zh, const char *name)
254 {
255     ZebraSet s;
256
257     for (s = zh->sets; s; s = s->next)
258         if (!strcmp (s->name, name))
259         {
260             if (!s->term_entries && !s->rset && s->rpn)
261             {
262                 NMEM nmem = nmem_create ();
263                 yaz_log (LOG_LOG, "research %s", name);
264                 s->rset =
265                     rpn_search (zh, nmem, s->rpn, s->num_bases,
266                                 s->basenames, s->name, s);
267                 nmem_destroy (nmem);
268             }
269             return s;
270         }
271     return NULL;
272 }
273
274 void resultSetInvalidate (ZebraHandle zh)
275 {
276     ZebraSet s = zh->sets;
277     
278     for (; s; s = s->next)
279     {
280         if (s->rset)
281         {
282             if (s->cache_rfd)
283                 rset_close(s->rset, s->cache_rfd);
284             rset_delete (s->rset);
285         }
286         s->rset = 0;
287         s->cache_rfd = 0;
288         s->cache_position = 0;
289     }
290 }
291
292 void resultSetDestroy (ZebraHandle zh, int num, char **names,int *statuses)
293 {
294     ZebraSet * ss = &zh->sets;
295     int i;
296     
297     if (statuses)
298         for (i = 0; i<num; i++)
299             statuses[i] = Z_DeleteStatus_resultSetDidNotExist;
300     zh->errCode = 0;
301     zh->errString = NULL;
302     while (*ss)
303     {
304         int i = -1;
305         ZebraSet s = *ss;
306         if (num >= 0)
307         {
308             for (i = 0; i<num; i++)
309                 if (!strcmp (s->name, names[i]))
310                 {
311                     if (statuses)
312                         statuses[i] = Z_DeleteStatus_success;
313                     i = -1;
314                     break;
315                 }
316         }
317         if (i < 0)
318         {
319             *ss = s->next;
320             
321             xfree (s->sort_info->all_entries);
322             xfree (s->sort_info->entries);
323             xfree (s->sort_info);
324             
325             if (s->nmem)
326                 nmem_destroy (s->nmem);
327             if (s->rset)
328             {
329                 if (s->cache_rfd)
330                     rset_close (s->rset, s->cache_rfd);
331                 rset_delete (s->rset);
332             }
333             xfree (s->name);
334             xfree (s);
335         }
336         else
337             ss = &s->next;
338     }
339 }
340
341 ZebraPosSet zebraPosSetCreate (ZebraHandle zh, const char *name, 
342                                int num, int *positions)
343 {
344     ZebraSet sset;
345     ZebraPosSet sr = 0;
346     RSET rset;
347     int i;
348     struct zset_sort_info *sort_info;
349
350     if (!(sset = resultSetGet (zh, name)))
351         return NULL;
352     if (!(rset = sset->rset))
353     {
354         if (!sset->term_entries)
355             return 0;
356         sr = (ZebraPosSet) xmalloc (sizeof(*sr) * num);
357         for (i = 0; i<num; i++)
358         {
359             sr[i].sysno = 0;
360             sr[i].score = -1;
361             sr[i].term = 0;
362             sr[i].db = 0;
363
364             if (positions[i] <= sset->term_entries_max)
365             {
366                 sr[i].term = sset->term_entries[positions[i]-1].term;
367                 sr[i].db = sset->term_entries[positions[i]-1].db;
368             }
369         }
370     }
371     else
372     {
373         sr = (ZebraPosSet) xmalloc (sizeof(*sr) * num);
374         for (i = 0; i<num; i++)
375         {
376             sr[i].sysno = 0;
377             sr[i].score = -1;
378             sr[i].term = 0;
379             sr[i].db = 0;
380         }
381         sort_info = sset->sort_info;
382         if (sort_info)
383         {
384             int position;
385             
386             for (i = 0; i<num; i++)
387             {
388                 position = positions[i];
389                 if (position > 0 && position <= sort_info->num_entries)
390                 {
391                     yaz_log (LOG_DEBUG, "got pos=%d (sorted)", position);
392                     sr[i].sysno = sort_info->entries[position-1]->sysno;
393                     sr[i].score = sort_info->entries[position-1]->score;
394                 }
395             }
396         }
397         /* did we really get all entries using sort ? */
398         for (i = 0; i<num; i++)
399         {
400             if (!sr[i].sysno)
401                 break;
402         }
403         if (i < num) /* nope, get the rest, unsorted - sorry */
404         {
405             int position = 0;
406             int num_i = 0;
407             int psysno = 0;
408             int term_index;
409             RSFD rfd;
410             struct it_key key;
411             
412             if (sort_info)
413                 position = sort_info->num_entries;
414             while (num_i < num && positions[num_i] < position)
415                 num_i++;
416             
417             if (sset->cache_rfd && 
418                 num_i < num && positions[num_i] > sset->cache_position)
419             {
420                 position = sset->cache_position;
421                 rfd = sset->cache_rfd;
422                 psysno = sset->cache_psysno;
423             } 
424             else
425             {
426                 if (sset->cache_rfd)
427                     rset_close(rset, sset->cache_rfd);
428                 rfd = rset_open (rset, RSETF_READ);
429             }
430             while (num_i < num && rset_read (rset, rfd, &key, &term_index))
431             {
432                 if (key.sysno != psysno)
433                 {
434                     psysno = key.sysno;
435                     if (sort_info)
436                     {
437                         /* determine we alreay have this in our set */
438                         for (i = sort_info->num_entries; --i >= 0; )
439                             if (psysno == sort_info->entries[i]->sysno)
440                                 break;
441                         if (i >= 0)
442                             continue;
443                     }
444                     position++;
445                     assert (num_i < num);
446                     if (position == positions[num_i])
447                     {
448                         sr[num_i].sysno = psysno;
449                         yaz_log (LOG_DEBUG, "got pos=%d (unsorted)", position);
450                         sr[num_i].score = -1;
451                         num_i++;
452                     }
453                 }
454             }
455             sset->cache_position = position;
456             sset->cache_psysno = psysno;
457             sset->cache_rfd = rfd;
458         }
459     }
460     return sr;
461 }
462
463 void zebraPosSetDestroy (ZebraHandle zh, ZebraPosSet records, int num)
464 {
465     xfree (records);
466 }
467
468 struct sortKeyInfo {
469     int relation;
470     int attrUse;
471     int numerical;
472 };
473
474 void resultSetInsertSort (ZebraHandle zh, ZebraSet sset,
475                           struct sortKeyInfo *criteria, int num_criteria,
476                           int sysno)
477 {
478     struct zset_sort_entry this_entry;
479     struct zset_sort_entry *new_entry = NULL;
480     struct zset_sort_info *sort_info = sset->sort_info;
481     int i, j;
482
483     sortIdx_sysno (zh->reg->sortIdx, sysno);
484     for (i = 0; i<num_criteria; i++)
485     {
486         sortIdx_type (zh->reg->sortIdx, criteria[i].attrUse);
487         sortIdx_read (zh->reg->sortIdx, this_entry.buf[i]);
488     }
489     i = sort_info->num_entries;
490     while (--i >= 0)
491     {
492         int rel = 0;
493         for (j = 0; j<num_criteria; j++)
494         {
495             if (criteria[j].numerical)
496             {
497                 double diff = atof(this_entry.buf[j]) -
498                               atof(sort_info->entries[i]->buf[j]);
499                 rel = 0;
500                 if (diff > 0.0)
501                     rel = 1;
502                 else if (diff < 0.0)
503                     rel = -1;
504             }
505             else
506             {
507                 rel = memcmp (this_entry.buf[j], sort_info->entries[i]->buf[j],
508                           SORT_IDX_ENTRYSIZE);
509             }
510             if (rel)
511                 break;
512         }       
513         if (!rel)
514             break;
515         if (criteria[j].relation == 'A')
516         {
517             if (rel > 0)
518                 break;
519         }
520         else if (criteria[j].relation == 'D')
521         {
522             if (rel < 0)
523                 break;
524         }
525     }
526     ++i;
527     j = sort_info->max_entries;
528     if (i == j)
529         return;
530
531     if (sort_info->num_entries == j)
532         --j;
533     else
534         j = (sort_info->num_entries)++;
535     new_entry = sort_info->entries[j];
536     while (j != i)
537     {
538         sort_info->entries[j] = sort_info->entries[j-1];
539         --j;
540     }
541     sort_info->entries[i] = new_entry;
542     assert (new_entry);
543     for (i = 0; i<num_criteria; i++)
544         memcpy (new_entry->buf[i], this_entry.buf[i], SORT_IDX_ENTRYSIZE);
545     new_entry->sysno = sysno;
546     new_entry->score = -1;
547 }
548
549 void resultSetInsertRank(ZebraHandle zh, struct zset_sort_info *sort_info,
550                          int sysno, int score, int relation)
551 {
552     struct zset_sort_entry *new_entry = NULL;
553     int i, j;
554
555     i = sort_info->num_entries;
556     while (--i >= 0)
557     {
558         int rel = 0;
559
560         rel = score - sort_info->entries[i]->score;
561
562         if (relation == 'D')
563         {
564             if (rel >= 0)
565                 break;
566         }
567         else if (relation == 'A')
568         {
569             if (rel <= 0)
570                 break;
571         }
572     }
573     ++i;
574     j = sort_info->max_entries;
575     if (i == j)
576         return;
577
578     if (sort_info->num_entries == j)
579         --j;
580     else
581         j = (sort_info->num_entries)++;
582     
583     new_entry = sort_info->entries[j];
584     while (j != i)
585     {
586         sort_info->entries[j] = sort_info->entries[j-1];
587         --j;
588     }
589     sort_info->entries[i] = new_entry;
590     assert (new_entry);
591     new_entry->sysno = sysno;
592     new_entry->score = score;
593 }
594
595 void resultSetSort (ZebraHandle zh, NMEM nmem,
596                     int num_input_setnames, const char **input_setnames,
597                     const char *output_setname,
598                     Z_SortKeySpecList *sort_sequence, int *sort_status)
599 {
600     ZebraSet sset;
601     RSET rset;
602
603     if (num_input_setnames == 0)
604     {
605         zh->errCode = 208;
606         return ;
607     }
608     if (num_input_setnames > 1)
609     {
610         zh->errCode = 230;
611         return;
612     }
613     yaz_log (LOG_DEBUG, "result set sort input=%s output=%s",
614           *input_setnames, output_setname);
615     sset = resultSetGet (zh, input_setnames[0]);
616     if (!sset)
617     {
618         zh->errCode = 30;
619         zh->errString = nmem_strdup (nmem, input_setnames[0]);
620         return;
621     }
622     if (!(rset = sset->rset))
623     {
624         zh->errCode = 30;
625         zh->errString = nmem_strdup (nmem, input_setnames[0]);
626         return;
627     }
628     if (strcmp (output_setname, input_setnames[0]))
629     {
630         rset = rset_dup (rset);
631         sset = resultSetAdd (zh, output_setname, 1);
632         sset->rset = rset;
633     }
634     resultSetSortSingle (zh, nmem, sset, rset, sort_sequence, sort_status);
635 }
636
637 void resultSetSortSingle (ZebraHandle zh, NMEM nmem,
638                           ZebraSet sset, RSET rset,
639                           Z_SortKeySpecList *sort_sequence, int *sort_status)
640 {
641     int kno = 0;
642     int i, psysno = 0;
643     struct it_key key;
644     struct sortKeyInfo sort_criteria[3];
645     int num_criteria;
646     int term_index;
647     RSFD rfd;
648
649     sset->sort_info->num_entries = 0;
650
651     sset->hits = 0;
652     num_criteria = sort_sequence->num_specs;
653     if (num_criteria > 3)
654         num_criteria = 3;
655     for (i = 0; i < num_criteria; i++)
656     {
657         Z_SortKeySpec *sks = sort_sequence->specs[i];
658         Z_SortKey *sk;
659
660         if (*sks->sortRelation == Z_SortKeySpec_ascending)
661             sort_criteria[i].relation = 'A';
662         else if (*sks->sortRelation == Z_SortKeySpec_descending)
663             sort_criteria[i].relation = 'D';
664         else
665         {
666             zh->errCode = 214;
667             return;
668         }
669         if (sks->sortElement->which == Z_SortElement_databaseSpecific)
670         {
671             zh->errCode = 210;
672             return;
673         }
674         else if (sks->sortElement->which != Z_SortElement_generic)
675         {
676             zh->errCode = 237;
677             return;
678         }       
679         sk = sks->sortElement->u.generic;
680         switch (sk->which)
681         {
682         case Z_SortKey_sortField:
683             yaz_log (LOG_DEBUG, "Sort: key %d is of type sortField", i+1);
684             zh->errCode = 207;
685             return;
686         case Z_SortKey_elementSpec:
687             yaz_log (LOG_DEBUG, "Sort: key %d is of type elementSpec", i+1);
688             zh->errCode = 207;
689             return;
690         case Z_SortKey_sortAttributes:
691             yaz_log (LOG_DEBUG, "Sort: key %d is of type sortAttributes", i+1);
692             sort_criteria[i].attrUse =
693                 zebra_maps_sort (zh->reg->zebra_maps,
694                                  sk->u.sortAttributes,
695                                  &sort_criteria[i].numerical);
696             yaz_log (LOG_DEBUG, "use value = %d", sort_criteria[i].attrUse);
697             if (sort_criteria[i].attrUse == -1)
698             {
699                 zh->errCode = 116;
700                 return;
701             }
702             if (sortIdx_type (zh->reg->sortIdx, sort_criteria[i].attrUse))
703             {
704                 zh->errCode = 207;
705                 return;
706             }
707             break;
708         }
709     }
710     rfd = rset_open (rset, RSETF_READ);
711     while (rset_read (rset, rfd, &key, &term_index))
712     {
713         kno++;
714         if (key.sysno != psysno)
715         {
716             (sset->hits)++;
717             psysno = key.sysno;
718             resultSetInsertSort (zh, sset,
719                                  sort_criteria, num_criteria, psysno);
720         }
721     }
722     rset_close (rset, rfd);
723
724     yaz_log (LOG_LOG, "%d keys, %d sysnos, sort", kno, sset->hits);
725     for (i = 0; i < rset->no_rset_terms; i++)
726         yaz_log (LOG_LOG, "term=\"%s\" nn=%d type=%s count=%d",
727                  rset->rset_terms[i]->name,
728                  rset->rset_terms[i]->nn,
729                  rset->rset_terms[i]->flags,
730                  rset->rset_terms[i]->count);
731
732     *sort_status = Z_SortResponse_success;
733 }
734
735 RSET resultSetRef (ZebraHandle zh, const char *resultSetId)
736 {
737     ZebraSet s;
738
739     if ((s = resultSetGet (zh, resultSetId)))
740         return s->rset;
741     return NULL;
742 }
743
744 void resultSetRank (ZebraHandle zh, ZebraSet zebraSet, RSET rset)
745 {
746     int kno = 0;
747     struct it_key key;
748     RSFD rfd;
749     int term_index, i;
750     ZebraRankClass rank_class;
751     struct rank_control *rc;
752     struct zset_sort_info *sort_info;
753     const char *rank_handler_name = res_get_def(zh->res, "rank", "rank-1");
754
755     sort_info = zebraSet->sort_info;
756     sort_info->num_entries = 0;
757     zebraSet->hits = 0;
758     rfd = rset_open (rset, RSETF_READ);
759
760     rank_class = zebraRankLookup (zh, rank_handler_name);
761     if (!rank_class)
762     {
763         yaz_log (LOG_WARN, "No such rank handler: %s", rank_handler_name);
764         return;
765     }
766     rc = rank_class->control;
767
768     if (rset_read (rset, rfd, &key, &term_index))
769     {
770         int psysno = key.sysno;
771         int score;
772         void *handle =
773             (*rc->begin) (zh->reg, rank_class->class_handle, rset);
774         (zebraSet->hits)++;
775         do
776         {
777             kno++;
778             if (key.sysno != psysno)
779             {
780                 score = (*rc->calc) (handle, psysno);
781
782                 resultSetInsertRank (zh, sort_info, psysno, score, 'A');
783                 (zebraSet->hits)++;
784                 psysno = key.sysno;
785             }
786             (*rc->add) (handle, key.seqno, term_index);
787         }
788         while (rset_read (rset, rfd, &key, &term_index));
789         score = (*rc->calc) (handle, psysno);
790         resultSetInsertRank (zh, sort_info, psysno, score, 'A');
791         (*rc->end) (zh->reg, handle);
792     }
793     rset_close (rset, rfd);
794
795     yaz_log (LOG_LOG, "%d keys, %d sysnos, rank", kno, zebraSet->hits);
796     for (i = 0; i < rset->no_rset_terms; i++)
797         yaz_log (LOG_LOG, "term=\"%s\" nn=%d type=%s count=%d",
798                  rset->rset_terms[i]->name,
799                  rset->rset_terms[i]->nn,
800                  rset->rset_terms[i]->flags,
801                  rset->rset_terms[i]->count);
802     
803 }
804
805 ZebraRankClass zebraRankLookup (ZebraHandle zh, const char *name)
806 {
807     ZebraRankClass p = zh->reg->rank_classes;
808     while (p && strcmp (p->control->name, name))
809         p = p->next;
810     if (p && !p->init_flag)
811     {
812         if (p->control->create)
813             p->class_handle = (*p->control->create)(zh);
814         p->init_flag = 1;
815     }
816     return p;
817 }
818
819 void zebraRankInstall (struct zebra_register *reg, struct rank_control *ctrl)
820 {
821     ZebraRankClass p = (ZebraRankClass) xmalloc (sizeof(*p));
822     p->control = (struct rank_control *) xmalloc (sizeof(*p->control));
823     memcpy (p->control, ctrl, sizeof(*p->control));
824     p->control->name = xstrdup (ctrl->name);
825     p->init_flag = 0;
826     p->next = reg->rank_classes;
827     reg->rank_classes = p;
828 }
829
830 void zebraRankDestroy (struct zebra_register *reg)
831 {
832     ZebraRankClass p = reg->rank_classes;
833     while (p)
834     {
835         ZebraRankClass p_next = p->next;
836         if (p->init_flag && p->control->destroy)
837             (*p->control->destroy)(reg, p->class_handle);
838         xfree (p->control->name);
839         xfree (p->control);
840         xfree (p);
841         p = p_next;
842     }
843     reg->rank_classes = NULL;
844 }