#include "LCBooleanScorer.h" #include "LCDisjunctionSumScorer.h" #include "LCConjunctionScorer.h" #include "LCReqExclScorer.h" #include "LCReqOptSumScorer.h" #include "LCDefaultSimilarity.h" #include "LCNonMatchingScorer.h" #include "GNUstep.h" /* LuceneKit: This is actually BooleanScorer2 in lucene */ @interface LCCoordinator: NSObject { int maxCoord; NSMutableArray *coordFactors; int nrMatchers; LCBooleanScorer *scorer; } - (id) initWithScorer: (LCBooleanScorer *) scorer; - (void) initiation; /* LuceneKit: init in lucene */ - (void) initiateDocument; - (float) coordFactor; - (int) maxCoord; - (void) setMaxCoord: (int) maxCoord; - (int) nrMatchers; - (void) setNrMatchers: (int) matchers; @end @interface LCBooleanDisjunctionSumScorer: LCDisjunctionSumScorer { LCCoordinator *coordinator; int lastScoredDoc; } - (id) initWithSubScorers: (NSArray *) subScorers minimumNrMatchers: (int) minimumNrMatchers coordinator: (LCCoordinator *) c; @end @interface LCBooleanConjunctionScorer: LCConjunctionScorer { LCCoordinator *coordinator; int requiredNrMatchers; int lastScoredDoc; } - (id) initWithSimilarity: (LCSimilarity *) similarity coordinator: (LCCoordinator *) c requiredNrMatchers: (int) required; @end @interface LCSingleMatchScorer: LCScorer { LCScorer *scorer; LCCoordinator *coordinator; int lastScoredDoc; } - (id) initWithScorer: (LCScorer *) scorer coordinator: (LCCoordinator *) coordinator; @end @interface LCBooleanScorer (LCPrivate) - (void) initCountingSumScorer; - (LCScorer *) countingDisjunctionSumScorer: (NSArray *) scorers minimumNumberShouldMatch: (int) min; - (LCScorer *) countingConjunctionSumScorer: (NSArray *) requiredScorers; - (LCScorer *) dualConjunctionSumScorer1: (LCScorer *) req1 scorer2: (LCScorer *) req2; - (LCScorer *) makeCountingSumScorer; - (LCScorer *) makeCountingSumScorerNoReq; - (LCScorer *) makeCountingSumScorerSomeReq; - (LCScorer *) addProhibitedScorers: (LCScorer *) requiredCountingSumScorer; @end @implementation LCBooleanScorer - (id) initWithSimilarity: (LCSimilarity *) s { return [self initWithSimilarity: s minimumNumberShouldMatch: 0]; } - (id) initWithSimilarity: (LCSimilarity *) s minimumNumberShouldMatch: (int) min { self = [super initWithSimilarity: s]; if (min < 0) { NSLog(@"Error: minimum number of optional scorers should not be negative"); return nil; } coordinator = [[LCCoordinator alloc] initWithScorer: self]; minNrShouldMatch = min; requiredScorers = [[NSMutableArray alloc] init]; optionalScorers = [[NSMutableArray alloc] init]; prohibitedScorers = [[NSMutableArray alloc] init]; countingSumScorer = nil; return self; } - (void) addScorer: (LCScorer *) scorer required: (BOOL) required prohibited: (BOOL) prohibited { if (!prohibited) { [coordinator setMaxCoord: [coordinator maxCoord] + 1]; } if (required) { if (prohibited) { NSLog(@"Scorer cannot be required and prohibited"); } [requiredScorers addObject: scorer]; } else if (prohibited) { [prohibitedScorers addObject: scorer]; } else { [optionalScorers addObject: scorer]; } } - (void) initCountingSumScorer { [coordinator initiation]; ASSIGN(countingSumScorer, [self makeCountingSumScorer]); } - (LCScorer *) countingDisjunctionSumScorer: (NSArray *) scorers minimumNumberShouldMatch: (int) min { return AUTORELEASE([[LCBooleanDisjunctionSumScorer alloc] initWithSubScorers: scorers minimumNrMatchers: min coordinator: coordinator]); } - (LCScorer *) countingConjunctionSumScorer: (NSArray *) scorers { int requiredNrMatchers = [scorers count]; // LuceneKit: Why always use LCDefaultSimilarity ? LCBooleanConjunctionScorer *cs = [[LCBooleanConjunctionScorer alloc] initWithSimilarity: AUTORELEASE([[LCDefaultSimilarity alloc] init]) coordinator: coordinator requiredNrMatchers: requiredNrMatchers]; NSEnumerator *e = [scorers objectEnumerator]; LCScorer *scorer; while ((scorer = [e nextObject])) { [cs addScorer: scorer]; } return AUTORELEASE(cs); } - (LCScorer *) dualConjunctionSumScorer1: (LCScorer *) req1 scorer2: (LCScorer *) req2 { int requiredNrMatchers = [requiredScorers count]; LCConjunctionScorer *cs = [[LCConjunctionScorer alloc] initWithSimilarity: similarity]; // All scorers match, so defaultSimilarity super.score() always has 1 as // the coordination factor. // Therefore the sum of the scores of two scorers // is used as score. [cs addScorer: req1]; [cs addScorer: req2]; return AUTORELEASE(cs); } - (LCScorer *) makeCountingSumScorer { if ([requiredScorers count] == 0) return [self makeCountingSumScorerNoReq]; else return [self makeCountingSumScorerSomeReq]; } - (LCScorer *) makeCountingSumScorerNoReq { // No required scorers #if 0 NSLog(@"LCBooleanScorer -makeCountingSumScorer"); NSLog(@"requiredScorers %@", requiredScorers); NSLog(@"optionalScorers %@", optionalScorers); NSLog(@"prohibitedScorers %@", prohibitedScorers); #endif if ([optionalScorers count] == 0) { return AUTORELEASE([[LCNonMatchingScorer alloc] init]); // no clauses or only prohibited scorers } else { // No required scorers. At least one optional scorer. // minNrShouldMatch optional scorers are quired, but at least 1 int nrOptRequired = (minNrShouldMatch < 1) ? 1 : minNrShouldMatch; if ([optionalScorers count] < nrOptRequired) { return AUTORELEASE([[LCNonMatchingScorer alloc] init]); // fewer optional clauses tham minimum (at least 1) that should match } else { // optionalScorers.size() >= nrOptRequired, no required scorers LCScorer *requiredCountingSumScorer; if ([optionalScorers count] > nrOptRequired) { requiredCountingSumScorer = [self countingDisjunctionSumScorer: optionalScorers minimumNumberShouldMatch: nrOptRequired]; } else { if ([optionalScorers count] == 1) { requiredCountingSumScorer = AUTORELEASE([[LCSingleMatchScorer alloc] initWithScorer: [optionalScorers objectAtIndex: 0] coordinator: coordinator]); } else { requiredCountingSumScorer = [self countingConjunctionSumScorer: optionalScorers]; } } return [self addProhibitedScorers: requiredCountingSumScorer]; } } } - (LCScorer *) makeCountingSumScorerSomeReq { // At least one required scorer #if 0 NSLog(@"LCBooleanScorer -makeCountingSumScorerSomeReq"); NSLog(@"minNrShouldMatch %d", minNrShouldMatch); #endif if ([optionalScorers count] < minNrShouldMatch) { return AUTORELEASE([[LCNonMatchingScorer alloc] init]); // fewer optional clauses than minimum that should match } else if ([optionalScorers count] == minNrShouldMatch) { // all optional scorers also required. NSMutableArray *allReq = [[NSMutableArray alloc] init]; [allReq addObjectsFromArray: requiredScorers]; [allReq addObjectsFromArray: optionalScorers]; return [self addProhibitedScorers: [self countingConjunctionSumScorer: allReq]]; } else { // optionalScorer.size() > minNrShouldMatch, and at least one required scorer LCScorer *requiredCountingSumScorer; if ([requiredScorers count] == 1) { requiredCountingSumScorer = [[LCSingleMatchScorer alloc] initWithScorer: [requiredScorers objectAtIndex: 0] coordinator: coordinator]; AUTORELEASE(requiredCountingSumScorer); } else { requiredCountingSumScorer = [self countingConjunctionSumScorer: requiredScorers]; } if (minNrShouldMatch > 0) { // use a required disjunction scorer over the optional scorers return [self addProhibitedScorers: [self dualConjunctionSumScorer1: requiredCountingSumScorer scorer2: [self countingDisjunctionSumScorer: optionalScorers minimumNumberShouldMatch: minNrShouldMatch]]]; } else { // minNrShouldMatch == 0 LCScorer *opt; if ([optionalScorers count] == 1) { opt = AUTORELEASE([[LCSingleMatchScorer alloc] initWithScorer: [optionalScorers objectAtIndex: 0] coordinator: coordinator]); } else { opt = [self countingDisjunctionSumScorer: optionalScorers minimumNumberShouldMatch: 1]; // required 1 in combined, optional scorer. } LCReqOptSumScorer *r = [[LCReqOptSumScorer alloc] initWithRequired: [self addProhibitedScorers: requiredCountingSumScorer] optional: opt]; return AUTORELEASE(r); } } } - (LCScorer *) addProhibitedScorers: (LCScorer *) requiredCountingSumScorer { RETAIN(requiredCountingSumScorer); //NSLog(@"AddProhibitedScorers %@", requiredCountingSumScorer); if ([prohibitedScorers count] == 0) { return AUTORELEASE(requiredCountingSumScorer); // no prohibited } else { LCScorer *ex; if ([prohibitedScorers count] == 1) { ex = [prohibitedScorers objectAtIndex: 0]; } else { ex = AUTORELEASE([[LCDisjunctionSumScorer alloc] initWithSubScorers: prohibitedScorers]); } return AUTORELEASE([[LCReqExclScorer alloc] initWithRequired: AUTORELEASE(requiredCountingSumScorer) excluded: ex]); } } - (void) score: (LCHitCollector *) hc { if (countingSumScorer == nil) { [self initCountingSumScorer]; } while ([countingSumScorer next]) { [hc collect: [countingSumScorer document] score: [self score]]; } } - (BOOL) score: (LCHitCollector *) hc maximalDocument: (int) max { int docNr = [countingSumScorer document]; while (docNr < max) { [hc collect: docNr score: [self score]]; if (![countingSumScorer next]) { return NO; } docNr = [countingSumScorer document]; } return YES; } - (int) document { return [countingSumScorer document]; } - (BOOL) next { if (countingSumScorer == nil) { [self initCountingSumScorer]; } return [countingSumScorer next]; } - (float) score { [coordinator initiateDocument]; float sum = [countingSumScorer score]; return (sum * [coordinator coordFactor]); } - (BOOL) skipTo: (int) target { if (countingSumScorer == nil) { [self initCountingSumScorer]; } return [countingSumScorer skipTo: target]; } - (LCExplanation *) explain: (int) doc { NSLog(@"not supported"); return nil; } @end @implementation LCBooleanConjunctionScorer - (id) initWithSimilarity: (LCSimilarity *) s coordinator: (LCCoordinator *) c requiredNrMatchers: (int) required { self = [super initWithSimilarity: s]; ASSIGN(coordinator, c); requiredNrMatchers = required; lastScoredDoc = -1; return self; } - (float) score { if ([self document] > lastScoredDoc) { lastScoredDoc = [self document]; [coordinator setNrMatchers: [coordinator nrMatchers] + requiredNrMatchers]; } return [super score]; } @end @implementation LCBooleanDisjunctionSumScorer - (id) initWithSubScorers: (NSArray *) sub minimumNrMatchers: (int) minimum coordinator: (LCCoordinator *) c { self = [super initWithSubScorers: sub minimumNrMatchers: minimum]; ASSIGN(coordinator, c); lastScoredDoc = -1; return self; } - (float) score { int t; if ([self document] > lastScoredDoc) { lastScoredDoc = [self document]; t = [coordinator nrMatchers] + [super nrMatchers]; [coordinator setNrMatchers: t]; } return [super score]; } @end @implementation LCSingleMatchScorer - (id) initWithScorer: (LCScorer *) s coordinator: (LCCoordinator *) c { self = [self initWithSimilarity: [s similarity]]; ASSIGN(scorer, s); ASSIGN(coordinator, c); lastScoredDoc = -1; return self; } - (float) score { if ([self document] > lastScoredDoc) { lastScoredDoc = [self document]; [coordinator setNrMatchers: [coordinator nrMatchers] + 1]; } return [scorer score]; } - (int) document { return [scorer document]; } - (BOOL) next { return [scorer next]; } - (BOOL) skipTo: (int) target { return [scorer skipTo: target]; } - (LCExplanation *) explain: (int) document { return [scorer explain: document]; } @end @implementation LCCoordinator - (id) initWithScorer: (LCBooleanScorer *) s { self = [self init]; ASSIGN(scorer, s); maxCoord = 0; return self; } - (void) initiation { coordFactors = [[NSMutableArray alloc] init]; LCSimilarity *sim = [scorer similarity]; int i; for (i = 0; i <= maxCoord; i++) { [coordFactors addObject: [NSNumber numberWithFloat: [sim coordination: i max: maxCoord]]]; } } - (void) initiateDocument { nrMatchers = 0; } - (float) coordFactor { return [[coordFactors objectAtIndex: nrMatchers] floatValue]; } - (int) maxCoord { return maxCoord; } - (void) setMaxCoord: (int) max { maxCoord = max; } - (int) nrMatchers { return nrMatchers; } - (void) setNrMatchers: (int) matchers { nrMatchers = matchers; } @end