blob: 2277300ca203c1f1155e3caa246b509ebac9b18f [file] [log] [blame]
/* 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_ANDMATCHER
#include "Lucy/Util/ToolSet.h"
#include "Lucy/Search/ANDMatcher.h"
#include "Lucy/Index/Similarity.h"
ANDMatcher*
ANDMatcher_new(VArray *children, Similarity *sim) {
ANDMatcher *self = (ANDMatcher*)VTable_Make_Obj(ANDMATCHER);
return ANDMatcher_init(self, children, sim);
}
ANDMatcher*
ANDMatcher_init(ANDMatcher *self, VArray *children, Similarity *sim) {
uint32_t i;
// Init.
PolyMatcher_init((PolyMatcher*)self, children, sim);
self->first_time = true;
// Assign.
self->more = self->num_kids ? true : false;
self->kids = (Matcher**)MALLOCATE(self->num_kids * sizeof(Matcher*));
for (i = 0; i < self->num_kids; i++) {
Matcher *child = (Matcher*)VA_Fetch(children, i);
self->kids[i] = child;
if (!Matcher_Next(child)) { self->more = false; }
}
// Derive.
self->matching_kids = self->num_kids;
return self;
}
void
ANDMatcher_destroy(ANDMatcher *self) {
FREEMEM(self->kids);
SUPER_DESTROY(self, ANDMATCHER);
}
int32_t
ANDMatcher_next(ANDMatcher *self) {
if (self->first_time) {
return ANDMatcher_Advance(self, 1);
}
if (self->more) {
const int32_t target = Matcher_Get_Doc_ID(self->kids[0]) + 1;
return ANDMatcher_Advance(self, target);
}
else {
return 0;
}
}
int32_t
ANDMatcher_advance(ANDMatcher *self, int32_t target) {
Matcher **const kids = self->kids;
const uint32_t num_kids = self->num_kids;
int32_t highest = 0;
if (!self->more) { return 0; }
// First step: Advance first child and use its doc as a starting point.
if (self->first_time) {
self->first_time = false;
}
else {
highest = Matcher_Advance(kids[0], target);
if (!highest) {
self->more = false;
return 0;
}
}
// Second step: reconcile.
while (1) {
uint32_t i;
bool_t agreement = true;
// Scoot all Matchers up.
for (i = 0; i < num_kids; i++) {
Matcher *const child = kids[i];
int32_t candidate = Matcher_Get_Doc_ID(child);
// If this child is highest, others will need to catch up.
if (highest < candidate) {
highest = candidate;
}
// If least doc Matchers can agree on exceeds target, raise bar.
if (target < highest) {
target = highest;
}
// Scoot this Matcher up if not already at highest.
if (candidate < target) {
// This Matcher is definitely the highest right now.
highest = Matcher_Advance(child, target);
if (!highest) {
self->more = false;
return 0;
}
}
}
// If Matchers don't agree, send back through the loop.
for (i = 0; i < num_kids; i++) {
Matcher *const child = kids[i];
const int32_t candidate = Matcher_Get_Doc_ID(child);
if (candidate != highest) {
agreement = false;
break;
}
}
if (!agreement) {
continue;
}
if (highest >= target) {
break;
}
}
return highest;
}
int32_t
ANDMatcher_get_doc_id(ANDMatcher *self) {
return Matcher_Get_Doc_ID(self->kids[0]);
}
float
ANDMatcher_score(ANDMatcher *self) {
uint32_t i;
Matcher **const kids = self->kids;
float score = 0.0f;
for (i = 0; i < self->num_kids; i++) {
score += Matcher_Score(kids[i]);
}
score *= self->coord_factors[self->matching_kids];
return score;
}