Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * tsrank.c
4 : : * rank tsvector by tsquery
5 : : *
6 : : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 : : *
8 : : *
9 : : * IDENTIFICATION
10 : : * src/backend/utils/adt/tsrank.c
11 : : *
12 : : *-------------------------------------------------------------------------
13 : : */
14 : : #include "postgres.h"
15 : :
16 : : #include <limits.h>
17 : : #include <math.h>
18 : :
19 : : #include "miscadmin.h"
20 : : #include "tsearch/ts_utils.h"
21 : : #include "utils/array.h"
22 : : #include "utils/fmgrprotos.h"
23 : :
24 : : #define NUM_WEIGHTS 4
25 : : static const float default_weights[NUM_WEIGHTS] = {0.1f, 0.2f, 0.4f, 1.0f};
26 : :
27 : : #define wpos(wep) ( w[ WEP_GETWEIGHT(wep) ] )
28 : :
29 : : #define RANK_NO_NORM 0x00
30 : : #define RANK_NORM_LOGLENGTH 0x01
31 : : #define RANK_NORM_LENGTH 0x02
32 : : #define RANK_NORM_EXTDIST 0x04
33 : : #define RANK_NORM_UNIQ 0x08
34 : : #define RANK_NORM_LOGUNIQ 0x10
35 : : #define RANK_NORM_RDIVRPLUS1 0x20
36 : : #define DEF_NORM_METHOD RANK_NO_NORM
37 : :
38 : : static float calc_rank_or(const float *w, TSVector t, TSQuery q);
39 : : static float calc_rank_and(const float *w, TSVector t, TSQuery q);
40 : :
41 : : /*
42 : : * Returns a weight of a word collocation
43 : : */
44 : : static float4
4821 peter_e@gmx.net 45 :CBC 9 : word_distance(int32 w)
46 : : {
6591 tgl@sss.pgh.pa.us 47 [ - + ]: 9 : if (w > 100)
6561 teodor@sigaev.ru 48 :UBC 0 : return 1e-30f;
49 : :
6591 tgl@sss.pgh.pa.us 50 :CBC 9 : return 1.0 / (1.005 + 0.05 * exp(((float4) w) / 1.5 - 2));
51 : : }
52 : :
53 : : static int
6591 tgl@sss.pgh.pa.us 54 :UBC 0 : cnt_length(TSVector t)
55 : : {
56 : 0 : WordEntry *ptr = ARRPTR(t),
57 : 0 : *end = (WordEntry *) STRPTR(t);
6570 teodor@sigaev.ru 58 : 0 : int len = 0;
59 : :
6591 tgl@sss.pgh.pa.us 60 [ # # ]: 0 : while (ptr < end)
61 : : {
6505 bruce@momjian.us 62 [ # # ]: 0 : int clen = POSDATALEN(t, ptr);
63 : :
6570 teodor@sigaev.ru 64 [ # # ]: 0 : if (clen == 0)
6591 tgl@sss.pgh.pa.us 65 : 0 : len += 1;
66 : : else
67 : 0 : len += clen;
68 : :
69 : 0 : ptr++;
70 : : }
71 : :
72 : 0 : return len;
73 : : }
74 : :
75 : :
76 : : #define WordECompareQueryItem(e,q,p,i,m) \
77 : : tsCompareString((q) + (i)->distance, (i)->length, \
78 : : (e) + (p)->pos, (p)->len, (m))
79 : :
80 : :
81 : : /*
82 : : * Returns a pointer to a WordEntry's array corresponding to 'item' from
83 : : * tsvector 't'. 'q' is the TSQuery containing 'item'.
84 : : * Returns NULL if not found.
85 : : */
86 : : static WordEntry *
6322 tgl@sss.pgh.pa.us 87 :CBC 213 : find_wordentry(TSVector t, TSQuery q, QueryOperand *item, int32 *nitem)
88 : : {
6591 89 : 213 : WordEntry *StopLow = ARRPTR(t);
90 : 213 : WordEntry *StopHigh = (WordEntry *) STRPTR(t);
6322 91 : 213 : WordEntry *StopMiddle = StopHigh;
92 : : int difference;
93 : :
5931 bruce@momjian.us 94 : 213 : *nitem = 0;
95 : :
96 : : /* Loop invariant: StopLow <= item < StopHigh */
6591 tgl@sss.pgh.pa.us 97 [ + + ]: 573 : while (StopLow < StopHigh)
98 : : {
99 : 549 : StopMiddle = StopLow + (StopHigh - StopLow) / 2;
6322 100 : 549 : difference = WordECompareQueryItem(STRPTR(t), GETOPERAND(q), StopMiddle, item, false);
6591 101 [ + + ]: 549 : if (difference == 0)
102 : : {
6322 103 : 189 : StopHigh = StopMiddle;
5931 bruce@momjian.us 104 : 189 : *nitem = 1;
6322 tgl@sss.pgh.pa.us 105 : 189 : break;
106 : : }
107 [ + + ]: 360 : else if (difference > 0)
6591 108 : 126 : StopLow = StopMiddle + 1;
109 : : else
110 : 234 : StopHigh = StopMiddle;
111 : : }
112 : :
5410 rhaas@postgresql.org 113 [ + + ]: 213 : if (item->prefix)
114 : : {
5931 bruce@momjian.us 115 [ + - ]: 27 : if (StopLow >= StopHigh)
6322 tgl@sss.pgh.pa.us 116 : 27 : StopMiddle = StopHigh;
117 : :
5931 bruce@momjian.us 118 : 27 : *nitem = 0;
119 : :
120 [ + + + - ]: 111 : while (StopMiddle < (WordEntry *) STRPTR(t) &&
121 : 42 : WordECompareQueryItem(STRPTR(t), GETOPERAND(q), StopMiddle, item, true) == 0)
122 : : {
6322 tgl@sss.pgh.pa.us 123 : 42 : (*nitem)++;
124 : 42 : StopMiddle++;
125 : : }
126 : : }
127 : :
5931 bruce@momjian.us 128 [ + + ]: 213 : return (*nitem > 0) ? StopHigh : NULL;
129 : : }
130 : :
131 : :
132 : : /*
133 : : * sort QueryOperands by (length, word)
134 : : */
135 : : static int
6574 teodor@sigaev.ru 136 : 54 : compareQueryOperand(const void *a, const void *b, void *arg)
137 : : {
6591 tgl@sss.pgh.pa.us 138 : 54 : char *operand = (char *) arg;
4836 bruce@momjian.us 139 : 54 : QueryOperand *qa = (*(QueryOperand *const *) a);
140 : 54 : QueryOperand *qb = (*(QueryOperand *const *) b);
141 : :
6322 tgl@sss.pgh.pa.us 142 : 108 : return tsCompareString(operand + qa->distance, qa->length,
143 : 54 : operand + qb->distance, qb->length,
144 : : false);
145 : : }
146 : :
147 : : /*
148 : : * Returns a sorted, de-duplicated array of QueryOperands in a query.
149 : : * The returned QueryOperands are pointers to the original QueryOperands
150 : : * in the query.
151 : : *
152 : : * Length of the returned array is stored in *size
153 : : */
154 : : static QueryOperand **
6574 teodor@sigaev.ru 155 : 27 : SortAndUniqItems(TSQuery q, int *size)
156 : : {
6505 bruce@momjian.us 157 : 27 : char *operand = GETOPERAND(q);
158 : 27 : QueryItem *item = GETQUERY(q);
159 : : QueryOperand **res,
160 : : **ptr,
161 : : **prevptr;
162 : :
6574 teodor@sigaev.ru 163 : 27 : ptr = res = (QueryOperand **) palloc(sizeof(QueryOperand *) * *size);
164 : :
165 : : /* Collect all operands from the tree to res */
6591 tgl@sss.pgh.pa.us 166 [ + + ]: 108 : while ((*size)--)
167 : : {
6574 teodor@sigaev.ru 168 [ + + ]: 81 : if (item->type == QI_VAL)
169 : : {
170 : 54 : *ptr = (QueryOperand *) item;
6591 tgl@sss.pgh.pa.us 171 : 54 : ptr++;
172 : : }
173 : 81 : item++;
174 : : }
175 : :
176 : 27 : *size = ptr - res;
177 [ - + ]: 27 : if (*size < 2)
6591 tgl@sss.pgh.pa.us 178 :UBC 0 : return res;
179 : :
942 peter@eisentraut.org 180 :CBC 27 : qsort_arg(res, *size, sizeof(QueryOperand *), compareQueryOperand, operand);
181 : :
6591 tgl@sss.pgh.pa.us 182 : 27 : ptr = res + 1;
183 : 27 : prevptr = res;
184 : :
185 : : /* remove duplicates */
186 [ + + ]: 54 : while (ptr - res < *size)
187 : : {
282 peter@eisentraut.org 188 [ + - ]: 27 : if (compareQueryOperand(ptr, prevptr, operand) != 0)
189 : : {
6591 tgl@sss.pgh.pa.us 190 : 27 : prevptr++;
191 : 27 : *prevptr = *ptr;
192 : : }
193 : 27 : ptr++;
194 : : }
195 : :
196 : 27 : *size = prevptr + 1 - res;
197 : 27 : return res;
198 : : }
199 : :
200 : : static float
4249 201 : 9 : calc_rank_and(const float *w, TSVector t, TSQuery q)
202 : : {
203 : : WordEntryPosVector **pos;
204 : : WordEntryPosVector1 posnull;
205 : : WordEntryPosVector *POSNULL;
206 : : int i,
207 : : k,
208 : : l,
209 : : p;
210 : : WordEntry *entry,
211 : : *firstentry;
212 : : WordEntryPos *post,
213 : : *ct;
214 : : int32 dimt,
215 : : lenct,
216 : : dist,
217 : : nitem;
6591 218 : 9 : float res = -1.0;
219 : : QueryOperand **item;
220 : 9 : int size = q->size;
221 : :
6574 teodor@sigaev.ru 222 : 9 : item = SortAndUniqItems(q, &size);
6591 tgl@sss.pgh.pa.us 223 [ - + ]: 9 : if (size < 2)
224 : : {
6591 tgl@sss.pgh.pa.us 225 :UBC 0 : pfree(item);
226 : 0 : return calc_rank_or(w, t, q);
227 : : }
6570 teodor@sigaev.ru 228 :CBC 9 : pos = (WordEntryPosVector **) palloc0(sizeof(WordEntryPosVector *) * q->size);
229 : :
230 : : /* A dummy WordEntryPos array to use when haspos is false */
3851 tgl@sss.pgh.pa.us 231 : 9 : posnull.npos = 1;
232 : 9 : posnull.pos[0] = 0;
233 : 9 : WEP_SETPOS(posnull.pos[0], MAXENTRYPOS - 1);
234 : 9 : POSNULL = (WordEntryPosVector *) &posnull;
235 : :
6591 236 [ + + ]: 27 : for (i = 0; i < size; i++)
237 : : {
6322 238 : 18 : firstentry = entry = find_wordentry(t, q, item[i], &nitem);
6591 239 [ - + ]: 18 : if (!entry)
6591 tgl@sss.pgh.pa.us 240 :UBC 0 : continue;
241 : :
5931 bruce@momjian.us 242 [ + + ]:CBC 36 : while (entry - firstentry < nitem)
243 : : {
6322 tgl@sss.pgh.pa.us 244 [ + - ]: 18 : if (entry->haspos)
245 : 18 : pos[i] = _POSVECPTR(t, entry);
246 : : else
3851 tgl@sss.pgh.pa.us 247 :UBC 0 : pos[i] = POSNULL;
248 : :
6322 tgl@sss.pgh.pa.us 249 :CBC 18 : dimt = pos[i]->npos;
250 : 18 : post = pos[i]->pos;
251 [ + + ]: 27 : for (k = 0; k < i; k++)
252 : : {
253 [ - + ]: 9 : if (!pos[k])
6322 tgl@sss.pgh.pa.us 254 :UBC 0 : continue;
6322 tgl@sss.pgh.pa.us 255 :CBC 9 : lenct = pos[k]->npos;
256 : 9 : ct = pos[k]->pos;
257 [ + + ]: 18 : for (l = 0; l < dimt; l++)
258 : : {
259 [ + + ]: 18 : for (p = 0; p < lenct; p++)
260 : : {
1065 peter@eisentraut.org 261 : 9 : dist = abs((int) WEP_GETPOS(post[l]) - (int) WEP_GETPOS(ct[p]));
3851 tgl@sss.pgh.pa.us 262 [ - + - - : 9 : if (dist || (dist == 0 && (pos[i] == POSNULL || pos[k] == POSNULL)))
- - - - ]
263 : : {
264 : : float curw;
265 : :
6322 266 [ - + ]: 9 : if (!dist)
6322 tgl@sss.pgh.pa.us 267 :UBC 0 : dist = MAXENTRYPOS;
6322 tgl@sss.pgh.pa.us 268 :CBC 9 : curw = sqrt(wpos(post[l]) * wpos(ct[p]) * word_distance(dist));
269 [ + - ]: 9 : res = (res < 0) ? curw : 1.0 - (1.0 - res) * (1.0 - curw);
270 : : }
271 : : }
272 : : }
273 : : }
274 : :
275 : 18 : entry++;
276 : : }
277 : : }
6591 278 : 9 : pfree(pos);
279 : 9 : pfree(item);
280 : 9 : return res;
281 : : }
282 : :
283 : : static float
4249 284 : 18 : calc_rank_or(const float *w, TSVector t, TSQuery q)
285 : : {
286 : : WordEntry *entry,
287 : : *firstentry;
288 : : WordEntryPosVector1 posnull;
289 : : WordEntryPos *post;
290 : : int32 dimt,
291 : : j,
292 : : i,
293 : : nitem;
6591 294 : 18 : float res = 0.0;
295 : : QueryOperand **item;
296 : 18 : int size = q->size;
297 : :
298 : : /* A dummy WordEntryPos array to use when haspos is false */
3851 299 : 18 : posnull.npos = 1;
300 : 18 : posnull.pos[0] = 0;
301 : :
6574 teodor@sigaev.ru 302 : 18 : item = SortAndUniqItems(q, &size);
303 : :
6591 tgl@sss.pgh.pa.us 304 [ + + ]: 54 : for (i = 0; i < size; i++)
305 : : {
306 : : float resj,
307 : : wjm;
308 : : int32 jm;
309 : :
6322 310 : 36 : firstentry = entry = find_wordentry(t, q, item[i], &nitem);
6591 311 [ + + ]: 36 : if (!entry)
312 : 3 : continue;
313 : :
5931 bruce@momjian.us 314 [ + + ]: 66 : while (entry - firstentry < nitem)
315 : : {
6322 tgl@sss.pgh.pa.us 316 [ + - ]: 33 : if (entry->haspos)
317 : : {
318 [ + - ]: 33 : dimt = POSDATALEN(t, entry);
319 : 33 : post = POSDATAPTR(t, entry);
320 : : }
321 : : else
322 : : {
3851 tgl@sss.pgh.pa.us 323 :UBC 0 : dimt = posnull.npos;
324 : 0 : post = posnull.pos;
325 : : }
326 : :
6322 tgl@sss.pgh.pa.us 327 :CBC 33 : resj = 0.0;
328 : 33 : wjm = -1.0;
329 : 33 : jm = 0;
330 [ + + ]: 66 : for (j = 0; j < dimt; j++)
331 : : {
332 : 33 : resj = resj + wpos(post[j]) / ((j + 1) * (j + 1));
333 [ + - ]: 33 : if (wpos(post[j]) > wjm)
334 : : {
335 : 33 : wjm = wpos(post[j]);
336 : 33 : jm = j;
337 : : }
338 : : }
339 : : /*
340 : : limit (sum(1/i^2),i=1,inf) = pi^2/6
341 : : resj = sum(wi/i^2),i=1,noccurrence,
342 : : wi - should be sorted desc,
343 : : don't sort for now, just choose maximum weight. This should be corrected
344 : : Oleg Bartunov
345 : : */
346 : 33 : res = res + (wjm + resj - wjm / ((jm + 1) * (jm + 1))) / 1.64493406685;
347 : :
348 : 33 : entry++;
349 : : }
350 : : }
6591 351 [ + - ]: 18 : if (size > 0)
352 : 18 : res = res / size;
353 : 18 : pfree(item);
354 : 18 : return res;
355 : : }
356 : :
357 : : static float
4249 358 : 27 : calc_rank(const float *w, TSVector t, TSQuery q, int32 method)
359 : : {
6591 360 : 27 : QueryItem *item = GETQUERY(q);
361 : 27 : float res = 0.0;
362 : : int len;
363 : :
364 [ + - - + ]: 27 : if (!t->size || !q->size)
6591 tgl@sss.pgh.pa.us 365 :UBC 0 : return 0.0;
366 : :
367 : : /* XXX: What about NOT? */
3439 teodor@sigaev.ru 368 [ + + ]:CBC 27 : res = (item->type == QI_OPR && (item->qoperator.oper == OP_AND ||
369 [ - + ]: 18 : item->qoperator.oper == OP_PHRASE)) ?
3376 rhaas@postgresql.org 370 [ + - ]: 36 : calc_rank_and(w, t, q) :
371 : 18 : calc_rank_or(w, t, q);
372 : :
6591 tgl@sss.pgh.pa.us 373 [ - + ]: 27 : if (res < 0)
6561 teodor@sigaev.ru 374 :UBC 0 : res = 1e-20f;
375 : :
6591 tgl@sss.pgh.pa.us 376 [ - + - - ]:CBC 27 : if ((method & RANK_NORM_LOGLENGTH) && t->size > 0)
6591 tgl@sss.pgh.pa.us 377 :UBC 0 : res /= log((double) (cnt_length(t) + 1)) / log(2.0);
378 : :
6591 tgl@sss.pgh.pa.us 379 [ - + ]:CBC 27 : if (method & RANK_NORM_LENGTH)
380 : : {
6591 tgl@sss.pgh.pa.us 381 :UBC 0 : len = cnt_length(t);
382 [ # # ]: 0 : if (len > 0)
383 : 0 : res /= (float) len;
384 : : }
385 : :
386 : : /* RANK_NORM_EXTDIST not applicable */
387 : :
6591 tgl@sss.pgh.pa.us 388 [ - + - - ]:CBC 27 : if ((method & RANK_NORM_UNIQ) && t->size > 0)
6591 tgl@sss.pgh.pa.us 389 :UBC 0 : res /= (float) (t->size);
390 : :
6591 tgl@sss.pgh.pa.us 391 [ - + - - ]:CBC 27 : if ((method & RANK_NORM_LOGUNIQ) && t->size > 0)
6591 tgl@sss.pgh.pa.us 392 :UBC 0 : res /= log((double) (t->size + 1)) / log(2.0);
393 : :
6506 tgl@sss.pgh.pa.us 394 [ - + ]:CBC 27 : if (method & RANK_NORM_RDIVRPLUS1)
6506 tgl@sss.pgh.pa.us 395 :UBC 0 : res /= (res + 1);
396 : :
6591 tgl@sss.pgh.pa.us 397 :CBC 27 : return res;
398 : : }
399 : :
400 : : /*
401 : : * Extract weights from an array. The weights are stored in *ws, which must
402 : : * have space for NUM_WEIGHTS elements.
403 : : */
404 : : static void
403 heikki.linnakangas@i 405 :UBC 0 : getWeights(ArrayType *win, float *ws)
406 : : {
407 : : int i;
408 : : float4 *arrdata;
409 : :
410 [ # # ]: 0 : Assert(win != NULL);
411 : :
6591 tgl@sss.pgh.pa.us 412 [ # # ]: 0 : if (ARR_NDIM(win) != 1)
413 [ # # ]: 0 : ereport(ERROR,
414 : : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
415 : : errmsg("array of weight must be one-dimensional")));
416 : :
403 heikki.linnakangas@i 417 [ # # ]: 0 : if (ArrayGetNItems(ARR_NDIM(win), ARR_DIMS(win)) < NUM_WEIGHTS)
6591 tgl@sss.pgh.pa.us 418 [ # # ]: 0 : ereport(ERROR,
419 : : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
420 : : errmsg("array of weight is too short")));
421 : :
5354 422 [ # # ]: 0 : if (array_contains_nulls(win))
6591 423 [ # # ]: 0 : ereport(ERROR,
424 : : (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
425 : : errmsg("array of weight must not contain nulls")));
426 : :
427 [ # # ]: 0 : arrdata = (float4 *) ARR_DATA_PTR(win);
403 heikki.linnakangas@i 428 [ # # ]: 0 : for (i = 0; i < NUM_WEIGHTS; i++)
429 : : {
430 [ # # ]: 0 : ws[i] = (arrdata[i] >= 0) ? arrdata[i] : default_weights[i];
6591 tgl@sss.pgh.pa.us 431 [ # # ]: 0 : if (ws[i] > 1.0)
432 [ # # ]: 0 : ereport(ERROR,
433 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
434 : : errmsg("weight out of range")));
435 : : }
436 : 0 : }
437 : :
438 : : Datum
439 : 0 : ts_rank_wttf(PG_FUNCTION_ARGS)
440 : : {
441 : 0 : ArrayType *win = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
442 : 0 : TSVector txt = PG_GETARG_TSVECTOR(1);
443 : 0 : TSQuery query = PG_GETARG_TSQUERY(2);
444 : 0 : int method = PG_GETARG_INT32(3);
445 : : float weights[NUM_WEIGHTS];
446 : : float res;
447 : :
403 heikki.linnakangas@i 448 : 0 : getWeights(win, weights);
449 : 0 : res = calc_rank(weights, txt, query, method);
450 : :
6591 tgl@sss.pgh.pa.us 451 [ # # ]: 0 : PG_FREE_IF_COPY(win, 0);
452 [ # # ]: 0 : PG_FREE_IF_COPY(txt, 1);
453 [ # # ]: 0 : PG_FREE_IF_COPY(query, 2);
454 : 0 : PG_RETURN_FLOAT4(res);
455 : : }
456 : :
457 : : Datum
458 : 0 : ts_rank_wtt(PG_FUNCTION_ARGS)
459 : : {
460 : 0 : ArrayType *win = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
461 : 0 : TSVector txt = PG_GETARG_TSVECTOR(1);
462 : 0 : TSQuery query = PG_GETARG_TSQUERY(2);
463 : : float weights[NUM_WEIGHTS];
464 : : float res;
465 : :
403 heikki.linnakangas@i 466 : 0 : getWeights(win, weights);
467 : 0 : res = calc_rank(weights, txt, query, DEF_NORM_METHOD);
468 : :
6591 tgl@sss.pgh.pa.us 469 [ # # ]: 0 : PG_FREE_IF_COPY(win, 0);
470 [ # # ]: 0 : PG_FREE_IF_COPY(txt, 1);
471 [ # # ]: 0 : PG_FREE_IF_COPY(query, 2);
472 : 0 : PG_RETURN_FLOAT4(res);
473 : : }
474 : :
475 : : Datum
476 : 0 : ts_rank_ttf(PG_FUNCTION_ARGS)
477 : : {
478 : 0 : TSVector txt = PG_GETARG_TSVECTOR(0);
479 : 0 : TSQuery query = PG_GETARG_TSQUERY(1);
480 : 0 : int method = PG_GETARG_INT32(2);
481 : : float res;
482 : :
403 heikki.linnakangas@i 483 : 0 : res = calc_rank(default_weights, txt, query, method);
484 : :
6591 tgl@sss.pgh.pa.us 485 [ # # ]: 0 : PG_FREE_IF_COPY(txt, 0);
486 [ # # ]: 0 : PG_FREE_IF_COPY(query, 1);
487 : 0 : PG_RETURN_FLOAT4(res);
488 : : }
489 : :
490 : : Datum
6591 tgl@sss.pgh.pa.us 491 :CBC 27 : ts_rank_tt(PG_FUNCTION_ARGS)
492 : : {
493 : 27 : TSVector txt = PG_GETARG_TSVECTOR(0);
494 : 27 : TSQuery query = PG_GETARG_TSQUERY(1);
495 : : float res;
496 : :
403 heikki.linnakangas@i 497 : 27 : res = calc_rank(default_weights, txt, query, DEF_NORM_METHOD);
498 : :
6591 tgl@sss.pgh.pa.us 499 [ - + ]: 27 : PG_FREE_IF_COPY(txt, 0);
500 [ - + ]: 27 : PG_FREE_IF_COPY(query, 1);
501 : 27 : PG_RETURN_FLOAT4(res);
502 : : }
503 : :
504 : : typedef struct
505 : : {
506 : : union
507 : : {
508 : : struct
509 : : { /* compiled doc representation */
510 : : QueryItem **items;
511 : : int16 nitem;
512 : : } query;
513 : : struct
514 : : { /* struct is used for preparing doc
515 : : * representation */
516 : : QueryItem *item;
517 : : WordEntry *entry;
518 : : } map;
519 : : } data;
520 : : WordEntryPos pos;
521 : : } DocRepresentation;
522 : :
523 : : static int
6570 teodor@sigaev.ru 524 : 174 : compareDocR(const void *va, const void *vb)
525 : : {
5109 peter_e@gmx.net 526 : 174 : const DocRepresentation *a = (const DocRepresentation *) va;
527 : 174 : const DocRepresentation *b = (const DocRepresentation *) vb;
528 : :
3439 teodor@sigaev.ru 529 [ + + ]: 174 : if (WEP_GETPOS(a->pos) == WEP_GETPOS(b->pos))
530 : : {
531 [ + + ]: 18 : if (WEP_GETWEIGHT(a->pos) == WEP_GETWEIGHT(b->pos))
532 : : {
533 [ + - ]: 3 : if (a->data.map.entry == b->data.map.entry)
534 : 3 : return 0;
535 : :
3439 teodor@sigaev.ru 536 [ # # ]:UBC 0 : return (a->data.map.entry > b->data.map.entry) ? 1 : -1;
537 : : }
538 : :
3439 teodor@sigaev.ru 539 [ + + ]:CBC 15 : return (WEP_GETWEIGHT(a->pos) > WEP_GETWEIGHT(b->pos)) ? 1 : -1;
540 : : }
541 : :
542 [ + + ]: 156 : return (WEP_GETPOS(a->pos) > WEP_GETPOS(b->pos)) ? 1 : -1;
543 : : }
544 : :
545 : : #define MAXQROPOS MAXENTRYPOS
546 : : typedef struct
547 : : {
548 : : bool operandexists;
549 : : bool reverseinsert; /* indicates insert order, true means
550 : : * descending order */
551 : : uint32 npos;
552 : : WordEntryPos pos[MAXQROPOS];
553 : : } QueryRepresentationOperand;
554 : :
555 : : typedef struct
556 : : {
557 : : TSQuery query;
558 : : QueryRepresentationOperand *operandData;
559 : : } QueryRepresentation;
560 : :
561 : : #define QR_GET_OPERAND_DATA(q, v) \
562 : : ( (q)->operandData + (((QueryItem*)(v)) - GETQUERY((q)->query)) )
563 : :
564 : : /*
565 : : * TS_execute callback for matching a tsquery operand to QueryRepresentation
566 : : */
567 : : static TSTernaryValue
1870 tgl@sss.pgh.pa.us 568 : 579 : checkcondition_QueryOperand(void *checkval, QueryOperand *val,
569 : : ExecPhraseData *data)
570 : : {
3376 rhaas@postgresql.org 571 : 579 : QueryRepresentation *qr = (QueryRepresentation *) checkval;
572 : 579 : QueryRepresentationOperand *opData = QR_GET_OPERAND_DATA(qr, val);
573 : :
3439 teodor@sigaev.ru 574 [ + + ]: 579 : if (!opData->operandexists)
1870 tgl@sss.pgh.pa.us 575 : 222 : return TS_NO;
576 : :
3439 teodor@sigaev.ru 577 [ + + ]: 357 : if (data)
578 : : {
579 : 174 : data->npos = opData->npos;
580 : 174 : data->pos = opData->pos;
581 [ + + ]: 174 : if (opData->reverseinsert)
582 : 54 : data->pos += MAXQROPOS - opData->npos;
583 : : }
584 : :
1870 tgl@sss.pgh.pa.us 585 : 357 : return TS_YES;
586 : : }
587 : :
588 : : typedef struct
589 : : {
590 : : int pos;
591 : : int p;
592 : : int q;
593 : : DocRepresentation *begin;
594 : : DocRepresentation *end;
595 : : } CoverExt;
596 : :
597 : : static void
3439 teodor@sigaev.ru 598 : 249 : resetQueryRepresentation(QueryRepresentation *qr, bool reverseinsert)
599 : : {
600 : : int i;
601 : :
3376 rhaas@postgresql.org 602 [ + + ]: 1008 : for (i = 0; i < qr->query->size; i++)
603 : : {
3439 teodor@sigaev.ru 604 : 759 : qr->operandData[i].operandexists = false;
605 : 759 : qr->operandData[i].reverseinsert = reverseinsert;
606 : 759 : qr->operandData[i].npos = 0;
607 : : }
608 : 249 : }
609 : :
610 : : static void
611 : 360 : fillQueryRepresentationData(QueryRepresentation *qr, DocRepresentation *entry)
612 : : {
613 : : int i;
614 : : int lastPos;
615 : : QueryRepresentationOperand *opData;
616 : :
617 [ + + ]: 723 : for (i = 0; i < entry->data.query.nitem; i++)
618 : : {
619 [ - + ]: 363 : if (entry->data.query.items[i]->type != QI_VAL)
3439 teodor@sigaev.ru 620 :UBC 0 : continue;
621 : :
3439 teodor@sigaev.ru 622 :CBC 363 : opData = QR_GET_OPERAND_DATA(qr, entry->data.query.items[i]);
623 : :
624 : 363 : opData->operandexists = true;
625 : :
626 [ + + ]: 363 : if (opData->npos == 0)
627 : : {
628 [ + + ]: 330 : lastPos = (opData->reverseinsert) ? (MAXQROPOS - 1) : 0;
629 : 330 : opData->pos[lastPos] = entry->pos;
630 : 330 : opData->npos++;
631 : 330 : continue;
632 : : }
633 : :
634 : 66 : lastPos = opData->reverseinsert ?
3376 rhaas@postgresql.org 635 [ - + ]: 33 : (MAXQROPOS - opData->npos) :
636 : 33 : (opData->npos - 1);
637 : :
3439 teodor@sigaev.ru 638 [ + + ]: 33 : if (WEP_GETPOS(opData->pos[lastPos]) != WEP_GETPOS(entry->pos))
639 : : {
640 : 42 : lastPos = opData->reverseinsert ?
3376 rhaas@postgresql.org 641 [ - + ]: 21 : (MAXQROPOS - 1 - opData->npos) :
642 : 21 : (opData->npos);
643 : :
3439 teodor@sigaev.ru 644 : 21 : opData->pos[lastPos] = entry->pos;
645 : 21 : opData->npos++;
646 : : }
647 : : }
648 : 360 : }
649 : :
650 : : static bool
4480 sfrost@snowman.net 651 : 162 : Cover(DocRepresentation *doc, int len, QueryRepresentation *qr, CoverExt *ext)
652 : : {
653 : : DocRepresentation *ptr;
3376 rhaas@postgresql.org 654 : 162 : int lastpos = ext->pos;
655 : 162 : bool found = false;
656 : :
657 : : /*
658 : : * since this function recurses, it could be driven to stack overflow.
659 : : * (though any decent compiler will optimize away the tail-recursion.
660 : : */
6574 teodor@sigaev.ru 661 : 162 : check_stack_depth();
662 : :
3439 663 : 162 : resetQueryRepresentation(qr, false);
664 : :
3818 andres@anarazel.de 665 : 162 : ext->p = INT_MAX;
6591 tgl@sss.pgh.pa.us 666 : 162 : ext->q = 0;
667 : 162 : ptr = doc + ext->pos;
668 : :
669 : : /* find upper bound of cover from current position, move up */
670 [ + + ]: 303 : while (ptr - doc < len)
671 : : {
3439 teodor@sigaev.ru 672 : 228 : fillQueryRepresentationData(qr, ptr);
673 : :
282 peter@eisentraut.org 674 [ + + ]: 228 : if (TS_execute(GETQUERY(qr->query), qr,
675 : : TS_EXEC_EMPTY, checkcondition_QueryOperand))
676 : : {
3439 teodor@sigaev.ru 677 [ + - ]: 87 : if (WEP_GETPOS(ptr->pos) > ext->q)
678 : : {
679 : 87 : ext->q = WEP_GETPOS(ptr->pos);
6591 tgl@sss.pgh.pa.us 680 : 87 : ext->end = ptr;
681 : 87 : lastpos = ptr - doc;
682 : 87 : found = true;
683 : : }
684 : 87 : break;
685 : : }
686 : 141 : ptr++;
687 : : }
688 : :
689 [ + + ]: 162 : if (!found)
690 : 75 : return false;
691 : :
3439 teodor@sigaev.ru 692 : 87 : resetQueryRepresentation(qr, true);
693 : :
6591 tgl@sss.pgh.pa.us 694 : 87 : ptr = doc + lastpos;
695 : :
696 : : /* find lower bound of cover from found upper bound, move down */
697 [ + - ]: 132 : while (ptr >= doc + ext->pos)
698 : : {
699 : : /*
700 : : * we scan doc from right to left, so pos info in reverse order!
701 : : */
3439 teodor@sigaev.ru 702 : 132 : fillQueryRepresentationData(qr, ptr);
703 : :
282 peter@eisentraut.org 704 [ + + ]: 132 : if (TS_execute(GETQUERY(qr->query), qr,
705 : : TS_EXEC_EMPTY, checkcondition_QueryOperand))
706 : : {
3439 teodor@sigaev.ru 707 [ + - ]: 87 : if (WEP_GETPOS(ptr->pos) < ext->p)
708 : : {
6591 tgl@sss.pgh.pa.us 709 : 87 : ext->begin = ptr;
3439 teodor@sigaev.ru 710 : 87 : ext->p = WEP_GETPOS(ptr->pos);
711 : : }
6591 tgl@sss.pgh.pa.us 712 : 87 : break;
713 : : }
714 : 45 : ptr--;
715 : : }
716 : :
717 [ + - ]: 87 : if (ext->p <= ext->q)
718 : : {
719 : : /*
720 : : * set position for next try to next lexeme after beginning of found
721 : : * cover
722 : : */
723 : 87 : ext->pos = (ptr - doc) + 1;
724 : 87 : return true;
725 : : }
726 : :
6591 tgl@sss.pgh.pa.us 727 :UBC 0 : ext->pos++;
6570 teodor@sigaev.ru 728 : 0 : return Cover(doc, len, qr, ext);
729 : : }
730 : :
731 : : static DocRepresentation *
6505 bruce@momjian.us 732 :CBC 78 : get_docrep(TSVector txt, QueryRepresentation *qr, int *doclen)
733 : : {
6570 teodor@sigaev.ru 734 : 78 : QueryItem *item = GETQUERY(qr->query);
735 : : WordEntry *entry,
736 : : *firstentry;
737 : : WordEntryPos *post;
738 : : int32 dimt, /* number of 'post' items */
739 : : j,
740 : : i,
741 : : nitem;
742 : 78 : int len = qr->query->size * 4,
6591 tgl@sss.pgh.pa.us 743 : 78 : cur = 0;
744 : : DocRepresentation *doc;
745 : :
746 : 78 : doc = (DocRepresentation *) palloc(sizeof(DocRepresentation) * len);
747 : :
748 : : /*
749 : : * Iterate through query to make DocRepresentation for words and it's
750 : : * entries satisfied by query
751 : : */
6570 teodor@sigaev.ru 752 [ + + ]: 318 : for (i = 0; i < qr->query->size; i++)
753 : : {
754 : : QueryOperand *curoperand;
755 : :
6574 756 [ + + ]: 240 : if (item[i].type != QI_VAL)
757 : 81 : continue;
758 : :
5896 peter_e@gmx.net 759 : 159 : curoperand = &item[i].qoperand;
760 : :
6322 tgl@sss.pgh.pa.us 761 : 159 : firstentry = entry = find_wordentry(txt, qr->query, curoperand, &nitem);
6591 762 [ + + ]: 159 : if (!entry)
763 : 3 : continue;
764 : :
765 : : /* iterations over entries in tsvector */
5931 bruce@momjian.us 766 [ + + ]: 327 : while (entry - firstentry < nitem)
767 : : {
6322 tgl@sss.pgh.pa.us 768 [ + + ]: 171 : if (entry->haspos)
769 : : {
770 [ + - ]: 165 : dimt = POSDATALEN(txt, entry);
771 : 165 : post = POSDATAPTR(txt, entry);
772 : : }
773 : : else
774 : : {
775 : : /* ignore words without positions */
4184 bruce@momjian.us 776 : 6 : entry++;
777 : 6 : continue;
778 : : }
779 : :
6322 tgl@sss.pgh.pa.us 780 [ - + ]: 165 : while (cur + dimt >= len)
781 : : {
6322 tgl@sss.pgh.pa.us 782 :UBC 0 : len *= 2;
783 : 0 : doc = (DocRepresentation *) repalloc(doc, sizeof(DocRepresentation) * len);
784 : : }
785 : :
786 : : /* iterations over entry's positions */
6322 tgl@sss.pgh.pa.us 787 [ + + ]:CBC 357 : for (j = 0; j < dimt; j++)
788 : : {
3439 teodor@sigaev.ru 789 [ + + ]: 192 : if (curoperand->weight == 0 ||
790 [ + + ]: 15 : curoperand->weight & (1 << WEP_GETWEIGHT(post[j])))
791 : : {
792 : 186 : doc[cur].pos = post[j];
793 : 186 : doc[cur].data.map.entry = entry;
794 : 186 : doc[cur].data.map.item = (QueryItem *) curoperand;
795 : 186 : cur++;
796 : : }
797 : : }
798 : :
6322 tgl@sss.pgh.pa.us 799 : 165 : entry++;
800 : : }
801 : : }
802 : :
6591 803 [ + + ]: 78 : if (cur > 0)
804 : : {
3376 rhaas@postgresql.org 805 : 75 : DocRepresentation *rptr = doc + 1,
806 : 75 : *wptr = doc,
807 : : storage;
808 : :
809 : : /*
810 : : * Sort representation in ascending order by pos and entry
811 : : */
942 peter@eisentraut.org 812 : 75 : qsort(doc, cur, sizeof(DocRepresentation), compareDocR);
813 : :
814 : : /*
815 : : * Join QueryItem per WordEntry and its position
816 : : */
3439 teodor@sigaev.ru 817 : 75 : storage.pos = doc->pos;
818 : 75 : storage.data.query.items = palloc(sizeof(QueryItem *) * qr->query->size);
819 : 75 : storage.data.query.items[0] = doc->data.map.item;
820 : 75 : storage.data.query.nitem = 1;
821 : :
822 [ + + ]: 186 : while (rptr - doc < cur)
823 : : {
3376 rhaas@postgresql.org 824 [ + + ]: 111 : if (rptr->pos == (rptr - 1)->pos &&
825 [ + - ]: 3 : rptr->data.map.entry == (rptr - 1)->data.map.entry)
826 : : {
3439 teodor@sigaev.ru 827 : 3 : storage.data.query.items[storage.data.query.nitem] = rptr->data.map.item;
828 : 3 : storage.data.query.nitem++;
829 : : }
830 : : else
831 : : {
832 : 108 : *wptr = storage;
833 : 108 : wptr++;
834 : 108 : storage.pos = rptr->pos;
835 : 108 : storage.data.query.items = palloc(sizeof(QueryItem *) * qr->query->size);
836 : 108 : storage.data.query.items[0] = rptr->data.map.item;
837 : 108 : storage.data.query.nitem = 1;
838 : : }
839 : :
840 : 111 : rptr++;
841 : : }
842 : :
843 : 75 : *wptr = storage;
844 : 75 : wptr++;
845 : :
846 : 75 : *doclen = wptr - doc;
6591 tgl@sss.pgh.pa.us 847 : 75 : return doc;
848 : : }
849 : :
850 : 3 : pfree(doc);
851 : 3 : return NULL;
852 : : }
853 : :
854 : : static float4
4249 855 : 78 : calc_rank_cd(const float4 *arrdata, TSVector txt, TSQuery query, int method)
856 : : {
857 : : DocRepresentation *doc;
858 : : int len,
859 : : i,
6591 860 : 78 : doclen = 0;
861 : : CoverExt ext;
862 : 78 : double Wdoc = 0.0;
863 : : double invws[NUM_WEIGHTS];
864 : 78 : double SumDist = 0.0,
1827 865 : 78 : PrevExtPos = 0.0;
6591 866 : 78 : int NExtent = 0;
867 : : QueryRepresentation qr;
868 : :
869 : :
403 heikki.linnakangas@i 870 [ + + ]: 390 : for (i = 0; i < NUM_WEIGHTS; i++)
871 : : {
872 [ + - ]: 312 : invws[i] = ((double) ((arrdata[i] >= 0) ? arrdata[i] : default_weights[i]));
6591 tgl@sss.pgh.pa.us 873 [ - + ]: 312 : if (invws[i] > 1.0)
6591 tgl@sss.pgh.pa.us 874 [ # # ]:UBC 0 : ereport(ERROR,
875 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
876 : : errmsg("weight out of range")));
6591 tgl@sss.pgh.pa.us 877 :CBC 312 : invws[i] = 1.0 / invws[i];
878 : : }
879 : :
6570 teodor@sigaev.ru 880 : 78 : qr.query = query;
3439 881 : 78 : qr.operandData = (QueryRepresentationOperand *)
3376 rhaas@postgresql.org 882 : 78 : palloc0(sizeof(QueryRepresentationOperand) * query->size);
883 : :
6570 teodor@sigaev.ru 884 : 78 : doc = get_docrep(txt, &qr, &doclen);
6591 tgl@sss.pgh.pa.us 885 [ + + ]: 78 : if (!doc)
886 : : {
3439 teodor@sigaev.ru 887 : 3 : pfree(qr.operandData);
6591 tgl@sss.pgh.pa.us 888 : 3 : return 0.0;
889 : : }
890 : :
4480 sfrost@snowman.net 891 [ + - + - : 375 : MemSet(&ext, 0, sizeof(CoverExt));
+ - + - +
+ ]
6570 teodor@sigaev.ru 892 [ + + ]: 162 : while (Cover(doc, doclen, &qr, &ext))
893 : : {
6591 tgl@sss.pgh.pa.us 894 : 87 : double Cpos = 0.0;
895 : 87 : double InvSum = 0.0;
896 : : double CurExtPos;
897 : : int nNoise;
898 : 87 : DocRepresentation *ptr = ext.begin;
899 : :
900 [ + + ]: 219 : while (ptr <= ext.end)
901 : : {
3439 teodor@sigaev.ru 902 : 132 : InvSum += invws[WEP_GETWEIGHT(ptr->pos)];
6591 tgl@sss.pgh.pa.us 903 : 132 : ptr++;
904 : : }
905 : :
906 : 87 : Cpos = ((double) (ext.end - ext.begin + 1)) / InvSum;
907 : :
908 : : /*
909 : : * if doc are big enough then ext.q may be equal to ext.p due to limit
910 : : * of positional information. In this case we approximate number of
911 : : * noise word as half cover's length
912 : : */
913 : 87 : nNoise = (ext.q - ext.p) - (ext.end - ext.begin);
914 [ - + ]: 87 : if (nNoise < 0)
6591 tgl@sss.pgh.pa.us 915 :UBC 0 : nNoise = (ext.end - ext.begin) / 2;
6591 tgl@sss.pgh.pa.us 916 :CBC 87 : Wdoc += Cpos / ((double) (1 + nNoise));
917 : :
918 : 87 : CurExtPos = ((double) (ext.q + ext.p)) / 2.0;
2999 919 [ + + + - ]: 87 : if (NExtent > 0 && CurExtPos > PrevExtPos /* prevent division by
920 : : * zero in a case of
921 : : * multiple lexize */ )
6591 922 : 21 : SumDist += 1.0 / (CurExtPos - PrevExtPos);
923 : :
924 : 87 : PrevExtPos = CurExtPos;
925 : 87 : NExtent++;
926 : : }
927 : :
928 [ - + - - ]: 75 : if ((method & RANK_NORM_LOGLENGTH) && txt->size > 0)
6591 tgl@sss.pgh.pa.us 929 :UBC 0 : Wdoc /= log((double) (cnt_length(txt) + 1));
930 : :
6591 tgl@sss.pgh.pa.us 931 [ - + ]:CBC 75 : if (method & RANK_NORM_LENGTH)
932 : : {
6591 tgl@sss.pgh.pa.us 933 :UBC 0 : len = cnt_length(txt);
934 [ # # ]: 0 : if (len > 0)
935 : 0 : Wdoc /= (double) len;
936 : : }
937 : :
6506 tgl@sss.pgh.pa.us 938 [ - + - - :CBC 75 : if ((method & RANK_NORM_EXTDIST) && NExtent > 0 && SumDist > 0)
- - ]
6591 tgl@sss.pgh.pa.us 939 :UBC 0 : Wdoc /= ((double) NExtent) / SumDist;
940 : :
6591 tgl@sss.pgh.pa.us 941 [ - + - - ]:CBC 75 : if ((method & RANK_NORM_UNIQ) && txt->size > 0)
6591 tgl@sss.pgh.pa.us 942 :UBC 0 : Wdoc /= (double) (txt->size);
943 : :
6591 tgl@sss.pgh.pa.us 944 [ - + - - ]:CBC 75 : if ((method & RANK_NORM_LOGUNIQ) && txt->size > 0)
6591 tgl@sss.pgh.pa.us 945 :UBC 0 : Wdoc /= log((double) (txt->size + 1)) / log(2.0);
946 : :
6506 tgl@sss.pgh.pa.us 947 [ - + ]:CBC 75 : if (method & RANK_NORM_RDIVRPLUS1)
6506 tgl@sss.pgh.pa.us 948 :UBC 0 : Wdoc /= (Wdoc + 1);
949 : :
6591 tgl@sss.pgh.pa.us 950 :CBC 75 : pfree(doc);
951 : :
3439 teodor@sigaev.ru 952 : 75 : pfree(qr.operandData);
953 : :
6591 tgl@sss.pgh.pa.us 954 : 75 : return (float4) Wdoc;
955 : : }
956 : :
957 : : Datum
6591 tgl@sss.pgh.pa.us 958 :UBC 0 : ts_rankcd_wttf(PG_FUNCTION_ARGS)
959 : : {
960 : 0 : ArrayType *win = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
961 : 0 : TSVector txt = PG_GETARG_TSVECTOR(1);
6570 teodor@sigaev.ru 962 : 0 : TSQuery query = PG_GETARG_TSQUERY(2);
6591 tgl@sss.pgh.pa.us 963 : 0 : int method = PG_GETARG_INT32(3);
964 : : float weights[NUM_WEIGHTS];
965 : : float res;
966 : :
403 heikki.linnakangas@i 967 : 0 : getWeights(win, weights);
968 : 0 : res = calc_rank_cd(weights, txt, query, method);
969 : :
6591 tgl@sss.pgh.pa.us 970 [ # # ]: 0 : PG_FREE_IF_COPY(win, 0);
971 [ # # ]: 0 : PG_FREE_IF_COPY(txt, 1);
972 [ # # ]: 0 : PG_FREE_IF_COPY(query, 2);
973 : 0 : PG_RETURN_FLOAT4(res);
974 : : }
975 : :
976 : : Datum
977 : 0 : ts_rankcd_wtt(PG_FUNCTION_ARGS)
978 : : {
979 : 0 : ArrayType *win = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
980 : 0 : TSVector txt = PG_GETARG_TSVECTOR(1);
6570 teodor@sigaev.ru 981 : 0 : TSQuery query = PG_GETARG_TSQUERY(2);
982 : : float weights[NUM_WEIGHTS];
983 : : float res;
984 : :
403 heikki.linnakangas@i 985 : 0 : getWeights(win, weights);
986 : 0 : res = calc_rank_cd(weights, txt, query, DEF_NORM_METHOD);
987 : :
6591 tgl@sss.pgh.pa.us 988 [ # # ]: 0 : PG_FREE_IF_COPY(win, 0);
989 [ # # ]: 0 : PG_FREE_IF_COPY(txt, 1);
990 [ # # ]: 0 : PG_FREE_IF_COPY(query, 2);
991 : 0 : PG_RETURN_FLOAT4(res);
992 : : }
993 : :
994 : : Datum
995 : 0 : ts_rankcd_ttf(PG_FUNCTION_ARGS)
996 : : {
997 : 0 : TSVector txt = PG_GETARG_TSVECTOR(0);
6570 teodor@sigaev.ru 998 : 0 : TSQuery query = PG_GETARG_TSQUERY(1);
6591 tgl@sss.pgh.pa.us 999 : 0 : int method = PG_GETARG_INT32(2);
1000 : : float res;
1001 : :
403 heikki.linnakangas@i 1002 : 0 : res = calc_rank_cd(default_weights, txt, query, method);
1003 : :
6591 tgl@sss.pgh.pa.us 1004 [ # # ]: 0 : PG_FREE_IF_COPY(txt, 0);
1005 [ # # ]: 0 : PG_FREE_IF_COPY(query, 1);
1006 : 0 : PG_RETURN_FLOAT4(res);
1007 : : }
1008 : :
1009 : : Datum
6591 tgl@sss.pgh.pa.us 1010 :CBC 78 : ts_rankcd_tt(PG_FUNCTION_ARGS)
1011 : : {
1012 : 78 : TSVector txt = PG_GETARG_TSVECTOR(0);
6570 teodor@sigaev.ru 1013 : 78 : TSQuery query = PG_GETARG_TSQUERY(1);
1014 : : float res;
1015 : :
403 heikki.linnakangas@i 1016 : 78 : res = calc_rank_cd(default_weights, txt, query, DEF_NORM_METHOD);
1017 : :
6591 tgl@sss.pgh.pa.us 1018 [ - + ]: 78 : PG_FREE_IF_COPY(txt, 0);
1019 [ - + ]: 78 : PG_FREE_IF_COPY(query, 1);
1020 : 78 : PG_RETURN_FLOAT4(res);
1021 : : }
|