/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define C_LUCY_LEXICONREADER
#define C_LUCY_POLYLEXICONREADER
#define C_LUCY_DEFAULTLEXICONREADER
#include "Lucy/Util/ToolSet.h"
#include "Lucy/Index/LexiconReader.h"
#include "Lucy/Plan/FieldType.h"
#include "Lucy/Plan/Schema.h"
#include "Lucy/Index/PolyLexicon.h"
#include "Lucy/Index/SegLexicon.h"
#include "Lucy/Index/Segment.h"
#include "Lucy/Index/Snapshot.h"
#include "Lucy/Index/TermInfo.h"
#include "Lucy/Store/Folder.h"
LexiconReader*
LexReader_init(LexiconReader *self, Schema *schema, Folder *folder,
Snapshot *snapshot, Vector *segments, int32_t seg_tick) {
DataReader_init((DataReader*)self, schema, folder, snapshot, segments,
seg_tick);
ABSTRACT_CLASS_CHECK(self, LEXICONREADER);
return self;
}
LexiconReader*
LexReader_Aggregator_IMP(LexiconReader *self, Vector *readers,
I32Array *offsets) {
UNUSED_VAR(self);
return (LexiconReader*)PolyLexReader_new(readers, offsets);
}
PolyLexiconReader*
PolyLexReader_new(Vector *readers, I32Array *offsets) {
PolyLexiconReader *self
= (PolyLexiconReader*)Class_Make_Obj(POLYLEXICONREADER);
return PolyLexReader_init(self, readers, offsets);
}
PolyLexiconReader*
PolyLexReader_init(PolyLexiconReader *self, Vector *readers,
I32Array *offsets) {
Schema *schema = NULL;
for (size_t i = 0, max = Vec_Get_Size(readers); i < max; i++) {
LexiconReader *reader
= (LexiconReader*)CERTIFY(Vec_Fetch(readers, i), LEXICONREADER);
if (!schema) { schema = LexReader_Get_Schema(reader); }
}
LexReader_init((LexiconReader*)self, schema, NULL, NULL, NULL, -1);
PolyLexiconReaderIVARS *const ivars = PolyLexReader_IVARS(self);
ivars->readers = (Vector*)INCREF(readers);
ivars->offsets = (I32Array*)INCREF(offsets);
return self;
}
void
PolyLexReader_Close_IMP(PolyLexiconReader *self) {
PolyLexiconReaderIVARS *const ivars = PolyLexReader_IVARS(self);
if (ivars->readers) {
for (size_t i = 0, max = Vec_Get_Size(ivars->readers); i < max; i++) {
LexiconReader *reader
= (LexiconReader*)Vec_Fetch(ivars->readers, i);
if (reader) { LexReader_Close(reader); }
}
Vec_Clear(ivars->readers);
}
}
void
PolyLexReader_Destroy_IMP(PolyLexiconReader *self) {
PolyLexiconReaderIVARS *const ivars = PolyLexReader_IVARS(self);
DECREF(ivars->readers);
DECREF(ivars->offsets);
SUPER_DESTROY(self, POLYLEXICONREADER);
}
Lexicon*
PolyLexReader_Lexicon_IMP(PolyLexiconReader *self, String *field,
Obj *term) {
PolyLexicon *lexicon = NULL;
if (field != NULL) {
Schema *schema = PolyLexReader_Get_Schema(self);
FieldType *type = Schema_Fetch_Type(schema, field);
if (type != NULL) {
PolyLexiconReaderIVARS *const ivars = PolyLexReader_IVARS(self);
lexicon = PolyLex_new(field, ivars->readers);
if (!PolyLex_Get_Num_Seg_Lexicons(lexicon)) {
DECREF(lexicon);
return NULL;
}
if (term) { PolyLex_Seek(lexicon, term); }
}
}
return (Lexicon*)lexicon;
}
uint32_t
PolyLexReader_Doc_Freq_IMP(PolyLexiconReader *self, String *field,
Obj *term) {
PolyLexiconReaderIVARS *const ivars = PolyLexReader_IVARS(self);
uint32_t doc_freq = 0;
for (size_t i = 0, max = Vec_Get_Size(ivars->readers); i < max; i++) {
LexiconReader *reader = (LexiconReader*)Vec_Fetch(ivars->readers, i);
if (reader) {
doc_freq += LexReader_Doc_Freq(reader, field, term);
}
}
return doc_freq;
}
DefaultLexiconReader*
DefLexReader_new(Schema *schema, Folder *folder, Snapshot *snapshot,
Vector *segments, int32_t seg_tick) {
DefaultLexiconReader *self
= (DefaultLexiconReader*)Class_Make_Obj(DEFAULTLEXICONREADER);
return DefLexReader_init(self, schema, folder, snapshot, segments,
seg_tick);
}
// Indicate whether it is safe to build a SegLexicon using the given
// parameters. Will return false if the field is not indexed or if no terms
// are present for this field in this segment.
static bool
S_has_data(Schema *schema, Folder *folder, Segment *segment, String *field) {
FieldType *type = Schema_Fetch_Type(schema, field);
if (!type || !FType_Indexed(type)) {
// If the field isn't indexed, bail out.
return false;
}
else {
// Bail out if there are no terms for this field in this segment.
int32_t field_num = Seg_Field_Num(segment, field);
String *seg_name = Seg_Get_Name(segment);
String *file = Str_newf("%o/lexicon-%i32.dat", seg_name, field_num);
bool retval = Folder_Exists(folder, file);
DECREF(file);
return retval;
}
}
DefaultLexiconReader*
DefLexReader_init(DefaultLexiconReader *self, Schema *schema, Folder *folder,
Snapshot *snapshot, Vector *segments, int32_t seg_tick) {
// Init.
LexReader_init((LexiconReader*)self, schema, folder, snapshot, segments,
seg_tick);
DefaultLexiconReaderIVARS *const ivars = DefLexReader_IVARS(self);
Segment *segment = DefLexReader_Get_Segment(self);
// Build an array of SegLexicon objects.
ivars->lexicons = Vec_new(Schema_Num_Fields(schema));
for (uint32_t i = 1, max = Schema_Num_Fields(schema) + 1; i < max; i++) {
String *field = Seg_Field_Name(segment, (int32_t)i);
if (field && S_has_data(schema, folder, segment, field)) {
SegLexicon *lexicon = SegLex_new(schema, folder, segment, field);
Vec_Store(ivars->lexicons, i, (Obj*)lexicon);
}
}
return self;
}
void
DefLexReader_Close_IMP(DefaultLexiconReader *self) {
DefaultLexiconReaderIVARS *const ivars = DefLexReader_IVARS(self);
DECREF(ivars->lexicons);
ivars->lexicons = NULL;
}
void
DefLexReader_Destroy_IMP(DefaultLexiconReader *self) {
DefaultLexiconReaderIVARS *const ivars = DefLexReader_IVARS(self);
DECREF(ivars->lexicons);
SUPER_DESTROY(self, DEFAULTLEXICONREADER);
}
Lexicon*
DefLexReader_Lexicon_IMP(DefaultLexiconReader *self, String *field,
Obj *term) {
DefaultLexiconReaderIVARS *const ivars = DefLexReader_IVARS(self);
int32_t field_num = Seg_Field_Num(ivars->segment, field);
SegLexicon *orig = (SegLexicon*)Vec_Fetch(ivars->lexicons, (size_t)field_num);
SegLexicon *lexicon = NULL;
if (orig) { // i.e. has data
lexicon
= SegLex_new(ivars->schema, ivars->folder, ivars->segment, field);
SegLex_Seek(lexicon, term);
}
return (Lexicon*)lexicon;
}
static TermInfo*
S_find_tinfo(DefaultLexiconReader *self, String *field, Obj *target) {
DefaultLexiconReaderIVARS *const ivars = DefLexReader_IVARS(self);
if (field != NULL && target != NULL) {
int32_t field_num = Seg_Field_Num(ivars->segment, field);
SegLexicon *lexicon
= (SegLexicon*)Vec_Fetch(ivars->lexicons, (size_t)field_num);
if (lexicon) {
// Iterate until the result is ge the term.
SegLex_Seek(lexicon, target);
//if found matches target, return info; otherwise NULL
Obj *found = SegLex_Get_Term(lexicon);
if (found && Obj_Equals(target, found)) {
return SegLex_Get_Term_Info(lexicon);
}
}
}
return NULL;
}
TermInfo*
DefLexReader_Fetch_Term_Info_IMP(DefaultLexiconReader *self,
String *field, Obj *target) {
TermInfo *tinfo = S_find_tinfo(self, field, target);
return tinfo ? TInfo_Clone(tinfo) : NULL;
}
uint32_t
DefLexReader_Doc_Freq_IMP(DefaultLexiconReader *self, String *field,
Obj *term) {
TermInfo *tinfo = S_find_tinfo(self, field, term);
return tinfo ? (uint32_t)TInfo_Get_Doc_Freq(tinfo) : 0;
}