Implemented automatic EXPLAIN database maintenance.
[idzebra-moved-to-github.git] / index / zsets.c
1 /*
2  * Copyright (C) 1994-1998, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: zsets.c,v $
7  * Revision 1.16  1998-05-20 10:12:24  adam
8  * Implemented automatic EXPLAIN database maintenance.
9  * Modified Zebra to work with ASN.1 compiled version of YAZ.
10  *
11  * Revision 1.15  1998/03/05 08:45:14  adam
12  * New result set model and modular ranking system. Moved towards
13  * descent server API. System information stored as "SGML" records.
14  *
15  * Revision 1.14  1998/02/10 16:39:15  adam
16  * Minor change.
17  *
18  * Revision 1.13  1998/02/10 12:03:06  adam
19  * Implemented Sort.
20  *
21  * Revision 1.12  1997/09/25 14:57:36  adam
22  * Windows NT port.
23  *
24  * Revision 1.11  1996/12/23 15:30:46  adam
25  * Work on truncation.
26  * Bug fix: result sets weren't deleted after server shut down.
27  *
28  * Revision 1.10  1995/10/30 15:08:08  adam
29  * Bug fixes.
30  *
31  * Revision 1.9  1995/10/17  18:02:14  adam
32  * New feature: databases. Implemented as prefix to words in dictionary.
33  *
34  * Revision 1.8  1995/10/10  13:59:25  adam
35  * Function rset_open changed its wflag parameter to general flags.
36  *
37  * Revision 1.7  1995/10/06  14:38:01  adam
38  * New result set method: r_score.
39  * Local no (sysno) and score is transferred to retrieveCtrl.
40  *
41  * Revision 1.6  1995/09/28  09:19:49  adam
42  * xfree/xmalloc used everywhere.
43  * Extract/retrieve method seems to work for text records.
44  *
45  * Revision 1.5  1995/09/27  16:17:32  adam
46  * More work on retrieve.
47  *
48  * Revision 1.4  1995/09/07  13:58:36  adam
49  * New parameter: result-set file descriptor (RSFD) to support multiple
50  * positions within the same result-set.
51  * Boolean operators: and, or, not implemented.
52  * Result-set references.
53  *
54  * Revision 1.3  1995/09/06  16:11:19  adam
55  * Option: only one word key per file.
56  *
57  * Revision 1.2  1995/09/06  10:33:04  adam
58  * More work on present. Some log messages removed.
59  *
60  * Revision 1.1  1995/09/05  15:28:40  adam
61  * More work on search engine.
62  *
63  */
64 #include <stdio.h>
65 #include <assert.h>
66 #ifdef WINDOWS
67 #include <io.h>
68 #else
69 #include <unistd.h>
70 #endif
71
72 #include "zserver.h"
73 #include <rstemp.h>
74
75 #define SORT_IDX_ENTRYSIZE 64
76 #define ZSET_SORT_MAX_LEVEL 3
77
78 struct zebra_set {
79     char *name;
80     RSET rset;
81     int size;
82     struct zset_sort_info *sort_info;
83     struct zebra_set *next;
84 };
85
86 struct zset_sort_entry {
87     int sysno;
88     int score;
89     char buf[ZSET_SORT_MAX_LEVEL][SORT_IDX_ENTRYSIZE];
90 };
91
92 struct zset_sort_info {
93     int max_entries;
94     int num_entries;
95     struct zset_sort_entry *all_entries;
96     struct zset_sort_entry **entries;
97 };
98
99 void resultSetRank (ZebraHandle zh, struct zset_sort_info *si,
100                     RSET rset, int *hits);
101
102 ZebraSet resultSetAdd (ZebraHandle zh, const char *name, int ov,
103                           RSET rset, int *hits)
104 {
105     ZebraSet s;
106     int i;
107
108     for (s = zh->sets; s; s = s->next)
109         if (!strcmp (s->name, name))
110         {
111             logf (LOG_DEBUG, "updating result set %s", name);
112             if (!ov)
113                 return NULL;
114             rset_delete (s->rset);
115             s->rset = rset;
116             resultSetRank (zh, s->sort_info, rset, hits);
117             return s;
118         }
119     logf (LOG_DEBUG, "adding result set %s", name);
120     s = xmalloc (sizeof(*s));
121     s->next = zh->sets;
122     zh->sets = s;
123     s->name = xmalloc (strlen(name)+1);
124     strcpy (s->name, name);
125     s->rset = rset;
126     
127     s->sort_info = xmalloc (sizeof(*s->sort_info));
128     s->sort_info->max_entries = 1000;
129     s->sort_info->entries = xmalloc (sizeof(*s->sort_info->entries) *
130                                      s->sort_info->max_entries);
131     s->sort_info->all_entries = xmalloc (sizeof(*s->sort_info->all_entries) *
132                                          s->sort_info->max_entries);
133     for (i = 0; i < s->sort_info->max_entries; i++)
134         s->sort_info->entries[i] = s->sort_info->all_entries + i;
135     resultSetRank (zh, s->sort_info, rset, hits);
136     return s;
137 }
138
139 ZebraSet resultSetGet (ZebraHandle zh, const char *name)
140 {
141     ZebraSet s;
142
143     for (s = zh->sets; s; s = s->next)
144         if (!strcmp (s->name, name))
145             return s;
146     return NULL;
147 }
148
149     
150 void resultSetDestroy (ZebraHandle zh)
151 {
152     ZebraSet s, s1;
153
154     for (s = zh->sets; s; s = s1)
155     {
156         s1 = s->next;
157
158         xfree (s->sort_info->all_entries);
159         xfree (s->sort_info->entries);
160         xfree (s->sort_info);
161
162         rset_delete (s->rset);
163         xfree (s->name);
164         xfree (s);
165     }
166     zh->sets = NULL;
167 }
168
169 ZebraPosSet zebraPosSetCreate (ZebraHandle zh, const char *name, 
170                                int num, int *positions)
171 {
172     ZebraSet sset;
173     ZebraPosSet sr;
174     RSET rset;
175     int i;
176     struct zset_sort_info *sort_info;
177
178     if (!(sset = resultSetGet (zh, name)))
179         return NULL;
180     if (!(rset = sset->rset))
181         return NULL;
182     sr = xmalloc (sizeof(*sr) * num);
183     for (i = 0; i<num; i++)
184     {
185         sr[i].sysno = 0;
186         sr[i].score = -1;
187     }
188     sort_info = sset->sort_info;
189     if (sort_info)
190     {
191         int position;
192
193         for (i = 0; i<num; i++)
194         {
195             position = positions[i];
196             if (position <= sort_info->num_entries)
197             {
198                 logf (LOG_DEBUG, "got pos=%d (sorted)", position);
199                 sr[i].sysno = sort_info->entries[position-1]->sysno;
200                 sr[i].score = sort_info->entries[position-1]->score;
201             }
202         }
203     }
204     /* did we really get all entries using sort ? */
205     for (i = 0; i<num; i++)
206     {
207         if (!sr[i].sysno)
208             break;
209     }
210     if (i < num) /* nope, get the rest, unsorted - sorry */
211     {
212         int position = 0;
213         int num_i = 0;
214         int psysno = 0;
215         int term_index;
216         RSFD rfd;
217         struct it_key key;
218
219         if (sort_info)
220             position = sort_info->num_entries;
221         while (num_i < num && positions[num_i] < position)
222             num_i++;
223         rfd = rset_open (rset, RSETF_READ);
224         while (num_i < num && rset_read (rset, rfd, &key, &term_index))
225         {
226             if (key.sysno != psysno)
227             {
228                 psysno = key.sysno;
229                 if (sort_info)
230                 {
231                     /* determine we alreay have this in our set */
232                     for (i = sort_info->num_entries; --i >= 0; )
233                         if (psysno == sort_info->entries[i]->sysno)
234                             break;
235                     if (i >= 0)
236                         continue;
237                 }
238                 position++;
239                 assert (num_i < num);
240                 if (position == positions[num_i])
241                 {
242                     sr[num_i].sysno = psysno;
243                     logf (LOG_DEBUG, "got pos=%d (unsorted)", position);
244                     sr[num_i].score = -1;
245                     num_i++;
246                 }
247             }
248         }
249         rset_close (rset, rfd);
250     }
251     return sr;
252 }
253
254 void zebraPosSetDestroy (ZebraHandle zh, ZebraPosSet records, int num)
255 {
256     xfree (records);
257 }
258
259 struct sortKey {
260     int relation;
261     int attrUse;
262 };
263
264 void resultSetInsertSort (ZebraHandle zh, ZebraSet sset,
265                           struct sortKey *criteria, int num_criteria,
266                           int sysno)
267 {
268     struct zset_sort_entry this_entry;
269     struct zset_sort_entry *new_entry = NULL;
270     struct zset_sort_info *sort_info = sset->sort_info;
271     int i, j;
272
273     sortIdx_sysno (zh->sortIdx, sysno);
274     for (i = 0; i<num_criteria; i++)
275     {
276         sortIdx_type (zh->sortIdx, criteria[i].attrUse);
277         sortIdx_read (zh->sortIdx, this_entry.buf[i]);
278     }
279     i = sort_info->num_entries;
280     while (--i >= 0)
281     {
282         int rel = 0;
283         for (j = 0; j<num_criteria; j++)
284         {
285             rel = memcmp (this_entry.buf[j], sort_info->entries[i]->buf[j],
286                           SORT_IDX_ENTRYSIZE);
287             if (rel)
288                 break;
289         }       
290         if (!rel)
291             break;
292         if (criteria[j].relation == 'D')
293         {
294             if (rel > 0)
295                 break;
296         }
297         else if (criteria[j].relation == 'A')
298         {
299             if (rel < 0)
300                 break;
301         }
302     }
303     j = sort_info->max_entries-1;
304     if (i == j)
305         return;
306     ++i;
307     new_entry = sort_info->entries[j];
308     while (j != i)
309     {
310         sort_info->entries[j] = sort_info->entries[j-1];
311         --j;
312     }
313     sort_info->entries[j] = new_entry;
314     assert (new_entry);
315     if (sort_info->num_entries != sort_info->max_entries)
316         (sort_info->num_entries)++;
317     for (i = 0; i<num_criteria; i++)
318         memcpy (new_entry->buf[i], this_entry.buf[i], SORT_IDX_ENTRYSIZE);
319     new_entry->sysno = sysno;
320     new_entry->score = -1;
321 }
322
323 void resultSetInsertRank (ZebraHandle zh, struct zset_sort_info *sort_info,
324                           int sysno, int score, int relation)
325 {
326     struct zset_sort_entry *new_entry = NULL;
327     int i, j;
328
329     i = sort_info->num_entries;
330     while (--i >= 0)
331     {
332         int rel = 0;
333
334         rel = score - sort_info->entries[i]->score;
335
336         if (relation == 'D')
337         {
338             if (rel >= 0)
339                 break;
340         }
341         else if (relation == 'A')
342         {
343             if (rel <= 0)
344                 break;
345         }
346     }
347     j = sort_info->max_entries-1;
348     if (i == j)
349         return;
350     ++i;
351     new_entry = sort_info->entries[j];
352     while (j != i)
353     {
354         sort_info->entries[j] = sort_info->entries[j-1];
355         --j;
356     }
357     sort_info->entries[j] = new_entry;
358     assert (new_entry);
359     if (sort_info->num_entries != sort_info->max_entries)
360         (sort_info->num_entries)++;
361     new_entry->sysno = sysno;
362     new_entry->score = score;
363 }
364
365 void resultSetSort (ZebraHandle zh, ODR stream,
366                     int num_input_setnames, char **input_setnames,
367                     char *output_setname, Z_SortKeySpecList *sort_sequence,
368                     int *sort_status)
369 {
370     ZebraSet sset;
371     RSET rset;
372     int i, psysno = 0;
373     struct it_key key;
374     struct sortKey sort_criteria[3];
375     int num_criteria;
376     int term_index;
377     RSFD rfd;
378
379     if (num_input_setnames == 0)
380     {
381         zh->errCode = 208;
382         return ;
383     }
384     if (num_input_setnames > 1)
385     {
386         zh->errCode = 230;
387         return;
388     }
389     sset = resultSetGet (zh, input_setnames[0]);
390     if (!sset)
391     {
392         zh->errCode = 30;
393         zh->errString = input_setnames[0];
394         return;
395     }
396     if (!(rset = sset->rset))
397     {
398         zh->errCode = 30;
399         zh->errString = input_setnames[0];
400         return;
401     }
402     num_criteria = sort_sequence->num_specs;
403     if (num_criteria > 3)
404         num_criteria = 3;
405     for (i = 0; i < num_criteria; i++)
406     {
407         Z_SortKeySpec *sks = sort_sequence->specs[i];
408         Z_SortKey *sk;
409
410         if (*sks->sortRelation == Z_SortRelation_ascending)
411             sort_criteria[i].relation = 'A';
412         else if (*sks->sortRelation == Z_SortRelation_descending)
413             sort_criteria[i].relation = 'D';
414         else
415         {
416             zh->errCode = 214;
417             return;
418         }
419         if (sks->sortElement->which == Z_SortElement_databaseSpecific)
420         {
421             zh->errCode = 210;
422             return;
423         }
424         else if (sks->sortElement->which != Z_SortElement_generic)
425         {
426             zh->errCode = 237;
427             return;
428         }       
429         sk = sks->sortElement->u.generic;
430         switch (sk->which)
431         {
432         case Z_SortKey_sortField:
433             logf (LOG_DEBUG, "Sort: key %d is of type sortField", i+1);
434             zh->errCode = 207;
435             return;
436         case Z_SortKey_elementSpec:
437             logf (LOG_DEBUG, "Sort: key %d is of type elementSpec", i+1);
438             zh->errCode = 207;
439             return;
440         case Z_SortKey_sortAttributes:
441             logf (LOG_DEBUG, "Sort: key %d is of type sortAttributes", i+1);
442             sort_criteria[i].attrUse =
443                 zebra_maps_sort (zh->zebra_maps, sk->u.sortAttributes);
444             logf (LOG_DEBUG, "use value = %d", sort_criteria[i].attrUse);
445             if (sort_criteria[i].attrUse == -1)
446             {
447                 zh->errCode = 116;
448                 return;
449             }
450             if (sortIdx_type (zh->sortIdx, sort_criteria[i].attrUse))
451             {
452                 zh->errCode = 207;
453                 return;
454             }
455             break;
456         }
457     }
458     if (strcmp (output_setname, input_setnames[0]))
459     {
460         int hits;
461         rset = rset_dup (rset);
462         sset = resultSetAdd (zh, output_setname, 1, rset, &hits);
463     }
464     sset->sort_info->num_entries = 0;
465
466     rfd = rset_open (rset, RSETF_READ);
467     while (rset_read (rset, rfd, &key, &term_index))
468     {
469         if (key.sysno != psysno)
470         {
471             psysno = key.sysno;
472             resultSetInsertSort (zh, sset,
473                                  sort_criteria, num_criteria, psysno);
474         }
475     }
476     rset_close (rset, rfd);
477
478     zh->errCode = 0;
479     *sort_status = Z_SortStatus_success;
480     
481     return;
482 }
483
484 RSET resultSetRef (ZebraHandle zh, Z_ResultSetId *resultSetId)
485 {
486     ZebraSet s;
487
488     if ((s = resultSetGet (zh, resultSetId)))
489         return s->rset;
490     return NULL;
491 }
492
493 void resultSetRank (ZebraHandle zh, struct zset_sort_info *sort_info,
494                     RSET rset, int *hits)
495 {
496     int kno = 0;
497     struct it_key key;
498     RSFD rfd;
499     int term_index, i;
500     ZebraRankClass rank_class;
501     struct rank_control *rc;
502
503     sort_info->num_entries = 0;
504     *hits = 0;
505     rfd = rset_open (rset, RSETF_READ);
506
507     logf (LOG_DEBUG, "resultSetRank");
508     for (i = 0; i < rset->no_rset_terms; i++)
509         logf (LOG_DEBUG, "term=\"%s\" cnt=%d type=%s",
510               rset->rset_terms[i]->name,
511               rset->rset_terms[i]->nn,
512               rset->rset_terms[i]->flags);
513
514     rank_class = zebraRankLookup (zh, "rank-1");
515     rc = rank_class->control;
516
517     if (rset_read (rset, rfd, &key, &term_index))
518     {
519         int psysno = key.sysno;
520         int score;
521         void *handle =
522             (*rc->begin) (zh, rank_class->class_handle, rset);
523         (*hits)++;
524         do
525         {
526             kno++;
527             if (key.sysno != psysno)
528             {
529                 score = (*rc->calc) (handle, psysno);
530
531                 resultSetInsertRank (zh, sort_info, psysno, score, 'A');
532                 (*hits)++;
533                 psysno = key.sysno;
534             }
535             (*rc->add) (handle, key.seqno, term_index);
536         }
537         while (rset_read (rset, rfd, &key, &term_index));
538         score = (*rc->calc) (handle, psysno);
539         resultSetInsertRank (zh, sort_info, psysno, score, 'A');
540         (*rc->end) (zh, handle);
541     }
542     rset_close (rset, rfd);
543     logf (LOG_DEBUG, "%d keys, %d distinct sysnos", kno, *hits);
544 }
545
546 ZebraRankClass zebraRankLookup (ZebraHandle zh, const char *name)
547 {
548     ZebraRankClass p = zh->rank_classes;
549     while (p && strcmp (p->control->name, name))
550         p = p->next;
551     if (p && !p->init_flag)
552     {
553         if (p->control->create)
554             p->class_handle = (*p->control->create)(zh);
555         p->init_flag = 1;
556     }
557     return p;
558 }
559
560 void zebraRankInstall (ZebraHandle zh, struct rank_control *ctrl)
561 {
562     ZebraRankClass p = xmalloc (sizeof(*p));
563     p->control = xmalloc (sizeof(*p->control));
564     memcpy (p->control, ctrl, sizeof(*p->control));
565     p->control->name = xstrdup (ctrl->name);
566     p->init_flag = 0;
567     p->next = zh->rank_classes;
568     zh->rank_classes = p;
569 }
570
571 void zebraRankDestroy (ZebraHandle zh)
572 {
573     ZebraRankClass p = zh->rank_classes;
574     while (p)
575     {
576         ZebraRankClass p_next = p->next;
577         if (p->init_flag && p->control->destroy)
578             (*p->control->destroy)(zh, p->class_handle);
579         xfree (p->control->name);
580         xfree (p->control);
581         xfree (p);
582         p = p_next;
583     }
584     zh->rank_classes = NULL;
585 }