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