#define KINO_USE_SHORT_NAMES
#include "KinoSearch/Util/ToolSet.h"
#define KINO_WANT_RICHPOSTING_VTABLE
#include "KinoSearch/Posting/RichPosting.r"
#include "KinoSearch/Analysis/Token.r"
#include "KinoSearch/Analysis/TokenBatch.r"
#include "KinoSearch/Index/PostingPool.r"
#include "KinoSearch/Posting/RawPosting.r"
#include "KinoSearch/Posting/RichPostingScorer.r"
#include "KinoSearch/FieldSpec.r"
#include "KinoSearch/Search/Similarity.r"
#include "KinoSearch/Store/InStream.r"
#include "KinoSearch/Util/MemoryPool.r"
#define FREQ_MAX_LEN VINT_MAX_BYTES
#define MAX_RAW_POSTING_LEN(_text_len, _freq) \
( sizeof(RawPosting) \
+ _text_len /* term text content */ \
+ FREQ_MAX_LEN /* freq vint */ \
+ (VINT_MAX_BYTES * _freq) /* positions deltas */ \
+ _freq /* per-pos boost byte */ \
)
RichPosting*
RichPost_new(Similarity *sim)
{
CREATE(self, RichPosting, RICHPOSTING);
/* init */
self->doc_num = DOC_NUM_SENTINEL;
self->freq = 0;
self->impact = 0.0;
self->prox = NULL;
self->prox_cap = 0;
self->prox_boosts = NULL;
/* assign */
self->sim = REFCOUNT_INC(sim);
return self;
}
void
RichPost_destroy(RichPosting *self)
{
REFCOUNT_DEC(self->sim);
free(self->prox);
free(self->prox_boosts);
free(self);
}
RichPosting*
RichPost_clone(RichPosting *self)
{
RichPosting *evil_twin = RichPost_new(self->sim);
*evil_twin = *self;
if (self->freq) {
evil_twin->prox_cap = evil_twin->freq;
evil_twin->prox = MALLOCATE(evil_twin->freq, u32_t);
evil_twin->prox_boosts = MALLOCATE(evil_twin->freq, float);
memcpy(evil_twin->prox, self->prox, self->freq * sizeof(u32_t));
memcpy(evil_twin->prox_boosts, self->prox_boosts,
self->freq * sizeof(float));
}
else {
evil_twin->prox = NULL;
evil_twin->prox_boosts = NULL;
}
return evil_twin;
}
RichPosting*
RichPost_dupe(RichPosting *self, Similarity *sim)
{
RichPosting *evil_twin = (RichPosting*)RichPost_Clone(self);
REFCOUNT_DEC(evil_twin->sim);
evil_twin->sim = REFCOUNT_INC(sim);
return evil_twin;
}
void
RichPost_read_record(RichPosting *self, InStream *instream)
{
float *const norm_decoder = self->sim->norm_decoder;
u32_t doc_code;
u32_t num_prox = 0;
u32_t position = 0;
u32_t *positions;
float *prox_boosts;
float aggregate_impact = 0.0;
/* decode delta doc */
doc_code = InStream_Read_VInt(instream);
self->doc_num += doc_code >> 1;
/* if the stored num was odd, the freq is 1 */
if (doc_code & 1) {
self->freq = 1;
}
/* otherwise, freq was stored as a VInt. */
else {
self->freq = InStream_Read_VInt(instream);
}
/* read positions, aggregate per-position boost byte into impact */
num_prox = self->freq;
if (num_prox > self->prox_cap) {
self->prox = REALLOCATE(self->prox, num_prox, u32_t);
self->prox_boosts = REALLOCATE(self->prox_boosts, num_prox, float);
}
positions = self->prox;
prox_boosts = self->prox_boosts;
while (num_prox--) {
position += InStream_Read_VInt(instream);
*positions++ = position;
*prox_boosts = norm_decoder[ (u8_t)InStream_Read_Byte(instream) ];
aggregate_impact += *prox_boosts;
prox_boosts++;
}
self->impact = aggregate_impact / self->freq;
}
void
RichPost_add_batch_to_pool(RichPosting *self, PostingPool *post_pool,
TokenBatch *batch, FieldSpec *fspec,
u32_t doc_num, float doc_boost, float length_norm)
{
MemoryPool *mem_pool = post_pool->mem_pool;
Similarity *sim = self->sim;
float field_boost = doc_boost * fspec->boost * length_norm;
Token **tokens;
u32_t freq;
TokenBatch_Reset(batch);
while ( (tokens = TokenBatch_Next_Cluster(batch, &freq)) != NULL ) {
Token *token = *tokens;
u32_t raw_post_bytes = MAX_RAW_POSTING_LEN(token->len, freq);
RawPosting *raw_posting = RawPost_new(
MemPool_Grab(mem_pool, raw_post_bytes), doc_num, freq,
token->text, token->len
);
char *const start = raw_posting->blob + token->len;
char *dest = start;
u32_t last_prox = 0;
u32_t i;
/* positions and boosts */
for (i = 0; i < freq; i++) {
Token *const t = tokens[i];
const u32_t prox_delta = t->pos - last_prox;
const float boost = field_boost * t->boost;
ENCODE_VINT(prox_delta, dest);
last_prox = t->pos;
*((u8_t*)dest) = Sim_Encode_Norm(sim, boost);
dest++;
}
/* resize raw posting memory allocation */
raw_posting->aux_len = dest - start;
raw_post_bytes = dest - (char*)raw_posting;
MemPool_Resize(mem_pool, raw_posting, raw_post_bytes);
PostPool_Add_Posting(post_pool, raw_posting);
}
}
RawPosting*
RichPost_read_raw(RichPosting *self, InStream *instream, u32_t last_doc_num,
ByteBuf *term_text, MemoryPool *mem_pool)
{
const u32_t doc_code = InStream_Read_VInt(instream);
const u32_t delta_doc = doc_code >> 1;
const u32_t doc_num = last_doc_num + delta_doc;
const u32_t freq = (doc_code & 1)
? 1
: InStream_Read_VInt(instream);
size_t raw_post_bytes = MAX_RAW_POSTING_LEN(term_text->len, freq);
void *const allocation = MemPool_Grab(mem_pool, raw_post_bytes);
RawPosting *const raw_posting = RawPost_new(allocation, doc_num, freq,
term_text->ptr, term_text->len);
u32_t num_prox = freq;
char *const start = raw_posting->blob + term_text->len;
char * dest = start;
UNUSED_VAR(self);
/* read positions and per-position boosts */
while (num_prox--) {
dest += InStream_Read_Raw_VLong(instream, dest);
*((u8_t*)dest) = (u8_t)InStream_Read_Byte(instream);
dest++;
}
/* resize raw posting memory allocation */
raw_posting->aux_len = dest - start;
raw_post_bytes = dest - (char*)raw_posting;
MemPool_Resize(mem_pool, raw_posting, raw_post_bytes);
return raw_posting;
}
RichPostingScorer*
RichPost_make_scorer(RichPosting *self, Similarity *sim,
struct kino_PostingList *plist,
void *weight, float weight_val)
{
UNUSED_VAR(self);
return RichPostScorer_new(sim, plist, weight, weight_val);
}
/* Copyright 2007 Marvin Humphrey
*
* This program is free software; you can redistribute it and/or modify
* under the same terms as Perl itself.
*/