Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  tsrank.c   Sprache: C

 

/*-------------------------------------------------------------------------
 *
 * tsrank.c
 *  rank tsvector by tsquery
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 *
 *
 * IDENTIFICATION
 *   src/backend/utils/adt/tsrank.c
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include <limits.h>
#include <math.h>

#include "miscadmin.h"
#include "tsearch/ts_utils.h"
#include "utils/array.h"
#include "utils/fmgrprotos.h"

#define NUM_WEIGHTS 4
static const float default_weights[NUM_WEIGHTS] = {0.1f, 0.2f, 0.4f, 1.0f};

#define wpos(wep) ( w[ WEP_GETWEIGHT(wep) ] )

#define RANK_NO_NORM   0x00
#define RANK_NORM_LOGLENGTH  0x01
#define RANK_NORM_LENGTH  0x02
#define RANK_NORM_EXTDIST  0x04
#define RANK_NORM_UNIQ   0x08
#define RANK_NORM_LOGUNIQ  0x10
#define RANK_NORM_RDIVRPLUS1 0x20
#define DEF_NORM_METHOD   RANK_NO_NORM

static float calc_rank_or(const float *w, TSVector t, TSQuery q);
static float calc_rank_and(const float *w, TSVector t, TSQuery q);

/*
 * Returns a weight of a word collocation
 */

static float4
word_distance(int32 w)
{
 if (w > 100)
  return 1e-30f;

 return 1.0 / (1.005 + 0.05 * exp(((float4) w) / 1.5 - 2));
}

static int
cnt_length(TSVector t)
{
 WordEntry  *ptr = ARRPTR(t),
      *end = (WordEntry *) STRPTR(t);
 int   len = 0;

 while (ptr < end)
 {
  int   clen = POSDATALEN(t, ptr);

  if (clen == 0)
   len += 1;
  else
   len += clen;

  ptr++;
 }

 return len;
}


#define WordECompareQueryItem(e,q,p,i,m) \
 tsCompareString((q) + (i)->distance, (i)->length, \
     (e) + (p)->pos, (p)->len, (m))


/*
 * Returns a pointer to a WordEntry's array corresponding to 'item' from
 * tsvector 't'. 'q' is the TSQuery containing 'item'.
 * Returns NULL if not found.
 */

static WordEntry *
find_wordentry(TSVector t, TSQuery q, QueryOperand *item, int32 *nitem)
{
 WordEntry  *StopLow = ARRPTR(t);
 WordEntry  *StopHigh = (WordEntry *) STRPTR(t);
 WordEntry  *StopMiddle = StopHigh;
 int   difference;

 *nitem = 0;

 /* Loop invariant: StopLow <= item < StopHigh */
 while (StopLow < StopHigh)
 {
  StopMiddle = StopLow + (StopHigh - StopLow) / 2;
  difference = WordECompareQueryItem(STRPTR(t), GETOPERAND(q), StopMiddle, item, false);
  if (difference == 0)
  {
   StopHigh = StopMiddle;
   *nitem = 1;
   break;
  }
  else if (difference > 0)
   StopLow = StopMiddle + 1;
  else
   StopHigh = StopMiddle;
 }

 if (item->prefix)
 {
  if (StopLow >= StopHigh)
   StopMiddle = StopHigh;

  *nitem = 0;

  while (StopMiddle < (WordEntry *) STRPTR(t) &&
      WordECompareQueryItem(STRPTR(t), GETOPERAND(q), StopMiddle, item, true) == 0)
  {
   (*nitem)++;
   StopMiddle++;
  }
 }

 return (*nitem > 0) ? StopHigh : NULL;
}


/*
 * sort QueryOperands by (length, word)
 */

static int
compareQueryOperand(const void *a, const void *b, void *arg)
{
 char    *operand = (char *) arg;
 QueryOperand *qa = (*(QueryOperand *const *) a);
 QueryOperand *qb = (*(QueryOperand *const *) b);

 return tsCompareString(operand + qa->distance, qa->length,
         operand + qb->distance, qb->length,
         false);
}

/*
 * Returns a sorted, de-duplicated array of QueryOperands in a query.
 * The returned QueryOperands are pointers to the original QueryOperands
 * in the query.
 *
 * Length of the returned array is stored in *size
 */

static QueryOperand **
SortAndUniqItems(TSQuery q, int *size)
{
 char    *operand = GETOPERAND(q);
 QueryItem  *item = GETQUERY(q);
 QueryOperand **res,
     **ptr,
     **prevptr;

 ptr = res = (QueryOperand **) palloc(sizeof(QueryOperand *) * *size);

 /* Collect all operands from the tree to res */
 while ((*size)--)
 {
  if (item->type == QI_VAL)
  {
   *ptr = (QueryOperand *) item;
   ptr++;
  }
  item++;
 }

 *size = ptr - res;
 if (*size < 2)
  return res;

 qsort_arg(res, *size, sizeof(QueryOperand *), compareQueryOperand, operand);

 ptr = res + 1;
 prevptr = res;

 /* remove duplicates */
 while (ptr - res < *size)
 {
  if (compareQueryOperand(ptr, prevptr, operand) != 0)
  {
   prevptr++;
   *prevptr = *ptr;
  }
  ptr++;
 }

 *size = prevptr + 1 - res;
 return res;
}

static float
calc_rank_and(const float *w, TSVector t, TSQuery q)
{
 WordEntryPosVector **pos;
 WordEntryPosVector1 posnull;
 WordEntryPosVector *POSNULL;
 int   i,
    k,
    l,
    p;
 WordEntry  *entry,
      *firstentry;
 WordEntryPos *post,
      *ct;
 int32  dimt,
    lenct,
    dist,
    nitem;
 float  res = -1.0;
 QueryOperand **item;
 int   size = q->size;

 item = SortAndUniqItems(q, &size);
 if (size < 2)
 {
  pfree(item);
  return calc_rank_or(w, t, q);
 }
 pos = (WordEntryPosVector **) palloc0(sizeof(WordEntryPosVector *) * q->size);

 /* A dummy WordEntryPos array to use when haspos is false */
 posnull.npos = 1;
 posnull.pos[0] = 0;
 WEP_SETPOS(posnull.pos[0], MAXENTRYPOS - 1);
 POSNULL = (WordEntryPosVector *) &posnull;

 for (i = 0; i < size; i++)
 {
  firstentry = entry = find_wordentry(t, q, item[i], &nitem);
  if (!entry)
   continue;

  while (entry - firstentry < nitem)
  {
   if (entry->haspos)
    pos[i] = _POSVECPTR(t, entry);
   else
    pos[i] = POSNULL;

   dimt = pos[i]->npos;
   post = pos[i]->pos;
   for (k = 0; k < i; k++)
   {
    if (!pos[k])
     continue;
    lenct = pos[k]->npos;
    ct = pos[k]->pos;
    for (l = 0; l < dimt; l++)
    {
     for (p = 0; p < lenct; p++)
     {
      dist = abs((int) WEP_GETPOS(post[l]) - (int) WEP_GETPOS(ct[p]));
      if (dist || (dist == 0 && (pos[i] == POSNULL || pos[k] == POSNULL)))
      {
       float  curw;

       if (!dist)
        dist = MAXENTRYPOS;
       curw = sqrt(wpos(post[l]) * wpos(ct[p]) * word_distance(dist));
       res = (res < 0) ? curw : 1.0 - (1.0 - res) * (1.0 - curw);
      }
     }
    }
   }

   entry++;
  }
 }
 pfree(pos);
 pfree(item);
 return res;
}

static float
calc_rank_or(const float *w, TSVector t, TSQuery q)
{
 WordEntry  *entry,
      *firstentry;
 WordEntryPosVector1 posnull;
 WordEntryPos *post;
 int32  dimt,
    j,
    i,
    nitem;
 float  res = 0.0;
 QueryOperand **item;
 int   size = q->size;

 /* A dummy WordEntryPos array to use when haspos is false */
 posnull.npos = 1;
 posnull.pos[0] = 0;

 item = SortAndUniqItems(q, &size);

 for (i = 0; i < size; i++)
 {
  float  resj,
     wjm;
  int32  jm;

  firstentry = entry = find_wordentry(t, q, item[i], &nitem);
  if (!entry)
   continue;

  while (entry - firstentry < nitem)
  {
   if (entry->haspos)
   {
    dimt = POSDATALEN(t, entry);
    post = POSDATAPTR(t, entry);
   }
   else
   {
    dimt = posnull.npos;
    post = posnull.pos;
   }

   resj = 0.0;
   wjm = -1.0;
   jm = 0;
   for (j = 0; j < dimt; j++)
   {
    resj = resj + wpos(post[j]) / ((j + 1) * (j + 1));
    if (wpos(post[j]) > wjm)
    {
     wjm = wpos(post[j]);
     jm = j;
    }
   }
/*
   limit (sum(1/i^2),i=1,inf) = pi^2/6
   resj = sum(wi/i^2),i=1,noccurrence,
   wi - should be sorted desc,
   don't sort for now, just choose maximum weight. This should be corrected
   Oleg Bartunov
*/

   res = res + (wjm + resj - wjm / ((jm + 1) * (jm + 1))) / 1.64493406685;

   entry++;
  }
 }
 if (size > 0)
  res = res / size;
 pfree(item);
 return res;
}

static float
calc_rank(const float *w, TSVector t, TSQuery q, int32 method)
{
 QueryItem  *item = GETQUERY(q);
 float  res = 0.0;
 int   len;

 if (!t->size || !q->size)
  return 0.0;

 /* XXX: What about NOT? */
 res = (item->type == QI_OPR && (item->qoperator.oper == OP_AND ||
         item->qoperator.oper == OP_PHRASE)) ?
  calc_rank_and(w, t, q) :
  calc_rank_or(w, t, q);

 if (res < 0)
  res = 1e-20f;

 if ((method & RANK_NORM_LOGLENGTH) && t->size > 0)
  res /= log((double) (cnt_length(t) + 1)) / log(2.0);

 if (method & RANK_NORM_LENGTH)
 {
  len = cnt_length(t);
  if (len > 0)
   res /= (float) len;
 }

 /* RANK_NORM_EXTDIST not applicable */

 if ((method & RANK_NORM_UNIQ) && t->size > 0)
  res /= (float) (t->size);

 if ((method & RANK_NORM_LOGUNIQ) && t->size > 0)
  res /= log((double) (t->size + 1)) / log(2.0);

 if (method & RANK_NORM_RDIVRPLUS1)
  res /= (res + 1);

 return res;
}

/*
 * Extract weights from an array. The weights are stored in *ws, which must
 * have space for NUM_WEIGHTS elements.
 */

static void
getWeights(ArrayType *win, float *ws)
{
 int   i;
 float4    *arrdata;

 Assert(win != NULL);

 if (ARR_NDIM(win) != 1)
  ereport(ERROR,
    (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     errmsg("array of weight must be one-dimensional")));

 if (ArrayGetNItems(ARR_NDIM(win), ARR_DIMS(win)) < NUM_WEIGHTS)
  ereport(ERROR,
    (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     errmsg("array of weight is too short")));

 if (array_contains_nulls(win))
  ereport(ERROR,
    (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
     errmsg("array of weight must not contain nulls")));

 arrdata = (float4 *) ARR_DATA_PTR(win);
 for (i = 0; i < NUM_WEIGHTS; i++)
 {
  ws[i] = (arrdata[i] >= 0) ? arrdata[i] : default_weights[i];
  if (ws[i] > 1.0)
   ereport(ERROR,
     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      errmsg("weight out of range")));
 }
}

Datum
ts_rank_wttf(PG_FUNCTION_ARGS)
{
 ArrayType  *win = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
 TSVector txt = PG_GETARG_TSVECTOR(1);
 TSQuery  query = PG_GETARG_TSQUERY(2);
 int   method = PG_GETARG_INT32(3);
 float  weights[NUM_WEIGHTS];
 float  res;

 getWeights(win, weights);
 res = calc_rank(weights, txt, query, method);

 PG_FREE_IF_COPY(win, 0);
 PG_FREE_IF_COPY(txt, 1);
 PG_FREE_IF_COPY(query, 2);
 PG_RETURN_FLOAT4(res);
}

Datum
ts_rank_wtt(PG_FUNCTION_ARGS)
{
 ArrayType  *win = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
 TSVector txt = PG_GETARG_TSVECTOR(1);
 TSQuery  query = PG_GETARG_TSQUERY(2);
 float  weights[NUM_WEIGHTS];
 float  res;

 getWeights(win, weights);
 res = calc_rank(weights, txt, query, DEF_NORM_METHOD);

 PG_FREE_IF_COPY(win, 0);
 PG_FREE_IF_COPY(txt, 1);
 PG_FREE_IF_COPY(query, 2);
 PG_RETURN_FLOAT4(res);
}

Datum
ts_rank_ttf(PG_FUNCTION_ARGS)
{
 TSVector txt = PG_GETARG_TSVECTOR(0);
 TSQuery  query = PG_GETARG_TSQUERY(1);
 int   method = PG_GETARG_INT32(2);
 float  res;

 res = calc_rank(default_weights, txt, query, method);

 PG_FREE_IF_COPY(txt, 0);
 PG_FREE_IF_COPY(query, 1);
 PG_RETURN_FLOAT4(res);
}

Datum
ts_rank_tt(PG_FUNCTION_ARGS)
{
 TSVector txt = PG_GETARG_TSVECTOR(0);
 TSQuery  query = PG_GETARG_TSQUERY(1);
 float  res;

 res = calc_rank(default_weights, txt, query, DEF_NORM_METHOD);

 PG_FREE_IF_COPY(txt, 0);
 PG_FREE_IF_COPY(query, 1);
 PG_RETURN_FLOAT4(res);
}

typedef struct
{
 union
 {
  struct
  {      /* compiled doc representation */
   QueryItem **items;
   int16  nitem;
  }   query;
  struct
  {      /* struct is used for preparing doc
 * representation */

   QueryItem  *item;
   WordEntry  *entry;
  }   map;
 }   data;
 WordEntryPos pos;
} DocRepresentation;

static int
compareDocR(const void *va, const void *vb)
{
 const DocRepresentation *a = (const DocRepresentation *) va;
 const DocRepresentation *b = (const DocRepresentation *) vb;

 if (WEP_GETPOS(a->pos) == WEP_GETPOS(b->pos))
 {
  if (WEP_GETWEIGHT(a->pos) == WEP_GETWEIGHT(b->pos))
  {
   if (a->data.map.entry == b->data.map.entry)
    return 0;

   return (a->data.map.entry > b->data.map.entry) ? 1 : -1;
  }

  return (WEP_GETWEIGHT(a->pos) > WEP_GETWEIGHT(b->pos)) ? 1 : -1;
 }

 return (WEP_GETPOS(a->pos) > WEP_GETPOS(b->pos)) ? 1 : -1;
}

#define MAXQROPOS MAXENTRYPOS
typedef struct
{
 bool  operandexists;
 bool  reverseinsert; /* indicates insert order, true means
 * descending order */

 uint32  npos;
 WordEntryPos pos[MAXQROPOS];
} QueryRepresentationOperand;

typedef struct
{
 TSQuery  query;
 QueryRepresentationOperand *operandData;
} QueryRepresentation;

#define QR_GET_OPERAND_DATA(q, v) \
 ( (q)->operandData + (((QueryItem*)(v)) - GETQUERY((q)->query)) )

/*
 * TS_execute callback for matching a tsquery operand to QueryRepresentation
 */

static TSTernaryValue
checkcondition_QueryOperand(void *checkval, QueryOperand *val,
       ExecPhraseData *data)
{
 QueryRepresentation *qr = (QueryRepresentation *) checkval;
 QueryRepresentationOperand *opData = QR_GET_OPERAND_DATA(qr, val);

 if (!opData->operandexists)
  return TS_NO;

 if (data)
 {
  data->npos = opData->npos;
  data->pos = opData->pos;
  if (opData->reverseinsert)
   data->pos += MAXQROPOS - opData->npos;
 }

 return TS_YES;
}

typedef struct
{
 int   pos;
 int   p;
 int   q;
 DocRepresentation *begin;
 DocRepresentation *end;
} CoverExt;

static void
resetQueryRepresentation(QueryRepresentation *qr, bool reverseinsert)
{
 int   i;

 for (i = 0; i < qr->query->size; i++)
 {
  qr->operandData[i].operandexists = false;
  qr->operandData[i].reverseinsert = reverseinsert;
  qr->operandData[i].npos = 0;
 }
}

static void
fillQueryRepresentationData(QueryRepresentation *qr, DocRepresentation *entry)
{
 int   i;
 int   lastPos;
 QueryRepresentationOperand *opData;

 for (i = 0; i < entry->data.query.nitem; i++)
 {
  if (entry->data.query.items[i]->type != QI_VAL)
   continue;

  opData = QR_GET_OPERAND_DATA(qr, entry->data.query.items[i]);

  opData->operandexists = true;

  if (opData->npos == 0)
  {
   lastPos = (opData->reverseinsert) ? (MAXQROPOS - 1) : 0;
   opData->pos[lastPos] = entry->pos;
   opData->npos++;
   continue;
  }

  lastPos = opData->reverseinsert ?
   (MAXQROPOS - opData->npos) :
   (opData->npos - 1);

  if (WEP_GETPOS(opData->pos[lastPos]) != WEP_GETPOS(entry->pos))
  {
   lastPos = opData->reverseinsert ?
    (MAXQROPOS - 1 - opData->npos) :
    (opData->npos);

   opData->pos[lastPos] = entry->pos;
   opData->npos++;
  }
 }
}

static bool
Cover(DocRepresentation *doc, int len, QueryRepresentation *qr, CoverExt *ext)
{
 DocRepresentation *ptr;
 int   lastpos = ext->pos;
 bool  found = false;

 /*
  * since this function recurses, it could be driven to stack overflow.
  * (though any decent compiler will optimize away the tail-recursion.
 */

 check_stack_depth();

 resetQueryRepresentation(qr, false);

 ext->p = INT_MAX;
 ext->q = 0;
 ptr = doc + ext->pos;

 /* find upper bound of cover from current position, move up */
 while (ptr - doc < len)
 {
  fillQueryRepresentationData(qr, ptr);

  if (TS_execute(GETQUERY(qr->query), qr,
        TS_EXEC_EMPTY, checkcondition_QueryOperand))
  {
   if (WEP_GETPOS(ptr->pos) > ext->q)
   {
    ext->q = WEP_GETPOS(ptr->pos);
    ext->end = ptr;
    lastpos = ptr - doc;
    found = true;
   }
   break;
  }
  ptr++;
 }

 if (!found)
  return false;

 resetQueryRepresentation(qr, true);

 ptr = doc + lastpos;

 /* find lower bound of cover from found upper bound, move down */
 while (ptr >= doc + ext->pos)
 {
  /*
   * we scan doc from right to left, so pos info in reverse order!
 */

  fillQueryRepresentationData(qr, ptr);

  if (TS_execute(GETQUERY(qr->query), qr,
        TS_EXEC_EMPTY, checkcondition_QueryOperand))
  {
   if (WEP_GETPOS(ptr->pos) < ext->p)
   {
    ext->begin = ptr;
    ext->p = WEP_GETPOS(ptr->pos);
   }
   break;
  }
  ptr--;
 }

 if (ext->p <= ext->q)
 {
  /*
   * set position for next try to next lexeme after beginning of found
   * cover
 */

  ext->pos = (ptr - doc) + 1;
  return true;
 }

 ext->pos++;
 return Cover(doc, len, qr, ext);
}

static DocRepresentation *
get_docrep(TSVector txt, QueryRepresentation *qr, int *doclen)
{
 QueryItem  *item = GETQUERY(qr->query);
 WordEntry  *entry,
      *firstentry;
 WordEntryPos *post;
 int32  dimt,   /* number of 'post' items */
    j,
    i,
    nitem;
 int   len = qr->query->size * 4,
    cur = 0;
 DocRepresentation *doc;

 doc = (DocRepresentation *) palloc(sizeof(DocRepresentation) * len);

 /*
  * Iterate through query to make DocRepresentation for words and it's
  * entries satisfied by query
 */

 for (i = 0; i < qr->query->size; i++)
 {
  QueryOperand *curoperand;

  if (item[i].type != QI_VAL)
   continue;

  curoperand = &item[i].qoperand;

  firstentry = entry = find_wordentry(txt, qr->query, curoperand, &nitem);
  if (!entry)
   continue;

  /* iterations over entries in tsvector */
  while (entry - firstentry < nitem)
  {
   if (entry->haspos)
   {
    dimt = POSDATALEN(txt, entry);
    post = POSDATAPTR(txt, entry);
   }
   else
   {
    /* ignore words without positions */
    entry++;
    continue;
   }

   while (cur + dimt >= len)
   {
    len *= 2;
    doc = (DocRepresentation *) repalloc(doc, sizeof(DocRepresentation) * len);
   }

   /* iterations over entry's positions */
   for (j = 0; j < dimt; j++)
   {
    if (curoperand->weight == 0 ||
     curoperand->weight & (1 << WEP_GETWEIGHT(post[j])))
    {
     doc[cur].pos = post[j];
     doc[cur].data.map.entry = entry;
     doc[cur].data.map.item = (QueryItem *) curoperand;
     cur++;
    }
   }

   entry++;
  }
 }

 if (cur > 0)
 {
  DocRepresentation *rptr = doc + 1,
       *wptr = doc,
     storage;

  /*
   * Sort representation in ascending order by pos and entry
 */

  qsort(doc, cur, sizeof(DocRepresentation), compareDocR);

  /*
   * Join QueryItem per WordEntry and its position
 */

  storage.pos = doc->pos;
  storage.data.query.items = palloc(sizeof(QueryItem *) * qr->query->size);
  storage.data.query.items[0] = doc->data.map.item;
  storage.data.query.nitem = 1;

  while (rptr - doc < cur)
  {
   if (rptr->pos == (rptr - 1)->pos &&
    rptr->data.map.entry == (rptr - 1)->data.map.entry)
   {
    storage.data.query.items[storage.data.query.nitem] = rptr->data.map.item;
    storage.data.query.nitem++;
   }
   else
   {
    *wptr = storage;
    wptr++;
    storage.pos = rptr->pos;
    storage.data.query.items = palloc(sizeof(QueryItem *) * qr->query->size);
    storage.data.query.items[0] = rptr->data.map.item;
    storage.data.query.nitem = 1;
   }

   rptr++;
  }

  *wptr = storage;
  wptr++;

  *doclen = wptr - doc;
  return doc;
 }

 pfree(doc);
 return NULL;
}

static float4
calc_rank_cd(const float4 *arrdata, TSVector txt, TSQuery query, int method)
{
 DocRepresentation *doc;
 int   len,
    i,
    doclen = 0;
 CoverExt ext;
 double  Wdoc = 0.0;
 double  invws[NUM_WEIGHTS];
 double  SumDist = 0.0,
    PrevExtPos = 0.0;
 int   NExtent = 0;
 QueryRepresentation qr;


 for (i = 0; i < NUM_WEIGHTS; i++)
 {
  invws[i] = ((double) ((arrdata[i] >= 0) ? arrdata[i] : default_weights[i]));
  if (invws[i] > 1.0)
   ereport(ERROR,
     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      errmsg("weight out of range")));
  invws[i] = 1.0 / invws[i];
 }

 qr.query = query;
 qr.operandData = (QueryRepresentationOperand *)
  palloc0(sizeof(QueryRepresentationOperand) * query->size);

 doc = get_docrep(txt, &qr, &doclen);
 if (!doc)
 {
  pfree(qr.operandData);
  return 0.0;
 }

 MemSet(&ext, 0, sizeof(CoverExt));
 while (Cover(doc, doclen, &qr, &ext))
 {
  double  Cpos = 0.0;
  double  InvSum = 0.0;
  double  CurExtPos;
  int   nNoise;
  DocRepresentation *ptr = ext.begin;

  while (ptr <= ext.end)
  {
   InvSum += invws[WEP_GETWEIGHT(ptr->pos)];
   ptr++;
  }

  Cpos = ((double) (ext.end - ext.begin + 1)) / InvSum;

  /*
   * if doc are big enough then ext.q may be equal to ext.p due to limit
   * of positional information. In this case we approximate number of
   * noise word as half cover's length
 */

  nNoise = (ext.q - ext.p) - (ext.end - ext.begin);
  if (nNoise < 0)
   nNoise = (ext.end - ext.begin) / 2;
  Wdoc += Cpos / ((double) (1 + nNoise));

  CurExtPos = ((double) (ext.q + ext.p)) / 2.0;
  if (NExtent > 0 && CurExtPos > PrevExtPos /* prevent division by
              * zero in a case of
  * multiple lexize */
 )
   SumDist += 1.0 / (CurExtPos - PrevExtPos);

  PrevExtPos = CurExtPos;
  NExtent++;
 }

 if ((method & RANK_NORM_LOGLENGTH) && txt->size > 0)
  Wdoc /= log((double) (cnt_length(txt) + 1));

 if (method & RANK_NORM_LENGTH)
 {
  len = cnt_length(txt);
  if (len > 0)
   Wdoc /= (double) len;
 }

 if ((method & RANK_NORM_EXTDIST) && NExtent > 0 && SumDist > 0)
  Wdoc /= ((double) NExtent) / SumDist;

 if ((method & RANK_NORM_UNIQ) && txt->size > 0)
  Wdoc /= (double) (txt->size);

 if ((method & RANK_NORM_LOGUNIQ) && txt->size > 0)
  Wdoc /= log((double) (txt->size + 1)) / log(2.0);

 if (method & RANK_NORM_RDIVRPLUS1)
  Wdoc /= (Wdoc + 1);

 pfree(doc);

 pfree(qr.operandData);

 return (float4) Wdoc;
}

Datum
ts_rankcd_wttf(PG_FUNCTION_ARGS)
{
 ArrayType  *win = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
 TSVector txt = PG_GETARG_TSVECTOR(1);
 TSQuery  query = PG_GETARG_TSQUERY(2);
 int   method = PG_GETARG_INT32(3);
 float  weights[NUM_WEIGHTS];
 float  res;

 getWeights(win, weights);
 res = calc_rank_cd(weights, txt, query, method);

 PG_FREE_IF_COPY(win, 0);
 PG_FREE_IF_COPY(txt, 1);
 PG_FREE_IF_COPY(query, 2);
 PG_RETURN_FLOAT4(res);
}

Datum
ts_rankcd_wtt(PG_FUNCTION_ARGS)
{
 ArrayType  *win = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
 TSVector txt = PG_GETARG_TSVECTOR(1);
 TSQuery  query = PG_GETARG_TSQUERY(2);
 float  weights[NUM_WEIGHTS];
 float  res;

 getWeights(win, weights);
 res = calc_rank_cd(weights, txt, query, DEF_NORM_METHOD);

 PG_FREE_IF_COPY(win, 0);
 PG_FREE_IF_COPY(txt, 1);
 PG_FREE_IF_COPY(query, 2);
 PG_RETURN_FLOAT4(res);
}

Datum
ts_rankcd_ttf(PG_FUNCTION_ARGS)
{
 TSVector txt = PG_GETARG_TSVECTOR(0);
 TSQuery  query = PG_GETARG_TSQUERY(1);
 int   method = PG_GETARG_INT32(2);
 float  res;

 res = calc_rank_cd(default_weights, txt, query, method);

 PG_FREE_IF_COPY(txt, 0);
 PG_FREE_IF_COPY(query, 1);
 PG_RETURN_FLOAT4(res);
}

Datum
ts_rankcd_tt(PG_FUNCTION_ARGS)
{
 TSVector txt = PG_GETARG_TSVECTOR(0);
 TSQuery  query = PG_GETARG_TSQUERY(1);
 float  res;

 res = calc_rank_cd(default_weights, txt, query, DEF_NORM_METHOD);

 PG_FREE_IF_COPY(txt, 0);
 PG_FREE_IF_COPY(query, 1);
 PG_RETURN_FLOAT4(res);
}

Messung V0.5 in Prozent
C=97 H=84 G=90

¤ Dauer der Verarbeitung: 0.4 Sekunden  (vorverarbeitet am  2026-09-28) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1126864
#Domains=1897691