1 /* $Id: rsprox.c,v 1.25 2005-03-08 14:02:15 adam Exp $
2 Copyright (C) 1995-2005
5 This file is part of the Zebra server.
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
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
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
35 static RSFD r_open (RSET ct, int flag);
36 static void r_close (RSFD rfd);
37 static void r_delete (RSET ct);
38 static int r_forward(RSFD rfd, void *buf, TERMID *term, const void *untilbuf);
39 static int r_read (RSFD rfd, void *buf, TERMID *term);
40 static int r_write (RSFD rfd, const void *buf);
41 static void r_pos (RSFD rfd, double *current, double *total);
42 static void r_get_terms(RSET ct, TERMID *terms, int maxterms, int *curterm);
44 static const struct rset_control control =
57 const struct rset_control *rset_kind_prox = &control;
59 struct rset_prox_info {
60 RSET *rset; /* array of 'child' rsets */
61 int rset_no; /* how many of them */
68 struct rset_prox_rfd {
70 char **buf; /* lookahead key buffers */
71 char *more; /* more in each lookahead? */
72 TERMID *terms; /* lookahead terms */
77 RSET rsprox_create( NMEM nmem, const struct key_control *kcontrol, int scope,
78 int rset_no, RSET *rset,
79 int ordered, int exclusion,
80 int relation, int distance)
82 RSET rnew = rset_create_base(&control, nmem, kcontrol, scope,0);
83 struct rset_prox_info *info;
84 info = (struct rset_prox_info *) nmem_malloc(rnew->nmem,sizeof(*info));
85 info->rset = nmem_malloc(rnew->nmem,rset_no * sizeof(*info->rset));
86 memcpy(info->rset, rset,
87 rset_no * sizeof(*info->rset));
88 info->rset_no = rset_no;
89 info->ordered = ordered;
90 info->exclusion = exclusion;
91 info->relation = relation;
92 info->distance = distance;
98 static void r_delete (RSET ct)
100 struct rset_prox_info *info = (struct rset_prox_info *) ct->priv;
103 for (i = 0; i<info->rset_no; i++)
104 rset_delete(info->rset[i]);
108 static RSFD r_open (RSET ct, int flag)
110 struct rset_prox_info *info = (struct rset_prox_info *) ct->priv;
112 struct rset_prox_rfd *p;
115 if (flag & RSETF_WRITE)
117 yaz_log(YLOG_FATAL, "prox set type is read-only");
120 rfd = rfd_create_base(ct);
122 p=(struct rset_prox_rfd *)(rfd->priv);
124 p = (struct rset_prox_rfd *) nmem_malloc(ct->nmem,sizeof(*p));
126 p->more = nmem_malloc (ct->nmem,sizeof(*p->more) * info->rset_no);
127 p->buf = nmem_malloc(ct->nmem,sizeof(*p->buf) * info->rset_no);
128 p->terms = nmem_malloc(ct->nmem,sizeof(*p->terms) * info->rset_no);
129 for (i = 0; i < info->rset_no; i++)
131 p->buf[i] = nmem_malloc(ct->nmem,ct->keycontrol->key_size);
134 p->rfd = nmem_malloc(ct->nmem,sizeof(*p->rfd) * info->rset_no);
136 yaz_log(YLOG_DEBUG,"rsprox (%s) open [%p] n=%d",
137 ct->control->desc, rfd, info->rset_no);
139 for (i = 0; i < info->rset_no; i++) {
140 p->rfd[i] = rset_open (info->rset[i], RSETF_READ);
141 p->more[i] = rset_read (p->rfd[i], p->buf[i], &p->terms[i]);
147 static void r_close (RSFD rfd)
149 struct rset_prox_info *info = (struct rset_prox_info *)(rfd->rset->priv);
150 struct rset_prox_rfd *p=(struct rset_prox_rfd *)(rfd->priv);
153 for (i = 0; i<info->rset_no; i++)
154 rset_close (p->rfd[i]);
155 rfd_delete_base(rfd);
158 static int r_forward (RSFD rfd, void *buf, TERMID *term, const void *untilbuf)
160 struct rset_prox_info *info = (struct rset_prox_info *)(rfd->rset->priv);
161 struct rset_prox_rfd *p=(struct rset_prox_rfd *)(rfd->priv);
162 const struct key_control *kctrl = rfd->rset->keycontrol;
168 /* it is enough to forward first one. Other will follow. */
169 if ( p->more[0] && /* was: cmp >=2 */
170 ((kctrl->cmp)(untilbuf, p->buf[0]) >= rfd->rset->scope) )
171 p->more[0] = rset_forward(p->rfd[0], p->buf[0],
172 &p->terms[0], untilbuf);
174 if (info->ordered && info->relation == 3 && info->exclusion == 0
175 && info->distance == 1)
179 for (i = 1; i < info->rset_no; i++)
183 p->more[0] = 0; /* saves us a goto out of while loop. */
186 cmp = (*kctrl->cmp) (p->buf[i], p->buf[i-1]);
187 if (cmp >= rfd->rset->scope ) /* cmp>1 */
189 p->more[i-1] = rset_forward (p->rfd[i-1],
195 else if ( cmp>0 ) /* cmp == 1*/
197 if ((*kctrl->getseq)(p->buf[i-1]) +1 !=
198 (*kctrl->getseq)(p->buf[i]))
199 { /* FIXME - We need more flexible multilevel stuff */
200 p->more[i-1] = rset_read ( p->rfd[i-1], p->buf[i-1],
207 p->more[i] = rset_forward (p->rfd[i],
208 p->buf[i], &p->terms[i], p->buf[i-1]);
212 if (i == info->rset_no)
214 memcpy (buf, p->buf[0], kctrl->key_size);
217 p->more[0] = rset_read (p->rfd[0], p->buf[0], &p->terms[0]);
223 else if (info->rset_no == 2)
225 while (p->more[0] && p->more[1])
227 int cmp = (*kctrl->cmp)(p->buf[0], p->buf[1]);
228 if ( cmp <= - rfd->rset->scope) /* cmp<-1*/
229 p->more[0] = rset_forward (p->rfd[0], p->buf[0],
230 &p->terms[0],p->buf[1]);
231 else if ( cmp >= rfd->rset->scope ) /* cmp>1 */
232 p->more[1] = rset_forward (p->rfd[1], p->buf[1],
233 &p->terms[1],p->buf[0]);
236 zint seqno[500]; /* FIXME - why 500 ?? */
239 seqno[n++] = (*kctrl->getseq)(p->buf[0]);
240 while ((p->more[0] = rset_read (p->rfd[0],
241 p->buf[0], &p->terms[0])) >= -1 &&
244 seqno[n++] = (*kctrl->getseq)(p->buf[0]);
246 for (i = 0; i<n; i++)
248 zint diff = (*kctrl->getseq)(p->buf[1]) - seqno[i];
249 int excl = info->exclusion;
250 if (!info->ordered && diff < 0)
252 switch (info->relation)
255 if (diff < info->distance && diff >= 0)
259 if (diff <= info->distance && diff >= 0)
263 if (diff == info->distance && diff >= 0)
267 if (diff >= info->distance && diff >= 0)
271 if (diff > info->distance && diff >= 0)
275 if (diff != info->distance && diff >= 0)
281 memcpy (buf, p->buf[1], kctrl->key_size);
284 p->more[1] = rset_read ( p->rfd[1], p->buf[1],
290 p->more[1] = rset_read (p->rfd[1], p->buf[1], &p->terms[1]);
298 static int r_read (RSFD rfd, void *buf, TERMID *term)
300 return r_forward(rfd, buf, term, 0);
303 static int r_write (RSFD rfd, const void *buf)
305 yaz_log(YLOG_FATAL, "prox set type is read-only");
309 static void r_pos (RSFD rfd, double *current, double *total)
311 struct rset_prox_info *info = (struct rset_prox_info *)(rfd->rset->priv);
312 struct rset_prox_rfd *p = (struct rset_prox_rfd *)(rfd->priv);
315 double cur, tot = -1.0;
316 double scur = 0.0, stot = 0.0;
318 yaz_log(YLOG_DEBUG, "rsprox_pos");
320 for (i = 0; i < info->rset_no; i++)
322 rset_pos(p->rfd[i], &cur, &tot);
328 if (tot <0) { /* nothing found */
331 } else if (tot < 1) { /* most likely tot==0 */
336 *current = (double) p->hits;
339 yaz_log(YLOG_DEBUG,"prox_pos: [%d] %0.1f/%0.1f= %0.4f ",
340 i,*current, *total, r);
345 static void r_get_terms(RSET ct, TERMID *terms, int maxterms, int *curterm)
347 struct rset_prox_info *info =
348 (struct rset_prox_info *) ct->priv;
350 for (i = 0; i<info->rset_no; i++)
351 rset_getterms(info->rset[i], terms, maxterms, curterm);