001: /*
002: * Copyright 2004-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.compass.core.lucene.engine.all;
018:
019: import java.io.IOException;
020:
021: import org.apache.lucene.index.IndexReader;
022: import org.apache.lucene.index.Term;
023: import org.apache.lucene.index.TermPositions;
024: import org.apache.lucene.search.Explanation;
025: import org.apache.lucene.search.Scorer;
026: import org.apache.lucene.search.Searcher;
027: import org.apache.lucene.search.Similarity;
028: import org.apache.lucene.search.Weight;
029: import org.apache.lucene.search.spans.SpanScorer;
030: import org.apache.lucene.search.spans.SpanTermQuery;
031: import org.apache.lucene.search.spans.SpanWeight;
032: import org.apache.lucene.search.spans.TermSpans;
033:
034: /**
035: * @author kimchy
036: */
037: public class AllBoostingTermQuery extends SpanTermQuery {
038:
039: public AllBoostingTermQuery(Term term) {
040: super (term);
041: }
042:
043: protected Weight createWeight(Searcher searcher) throws IOException {
044: return new AllBoostingTermWeight(this , searcher);
045: }
046:
047: protected class AllBoostingTermWeight extends SpanWeight implements
048: Weight {
049:
050: public AllBoostingTermWeight(AllBoostingTermQuery query,
051: Searcher searcher) throws IOException {
052: super (query, searcher);
053: }
054:
055: public Scorer scorer(IndexReader reader) throws IOException {
056: return new BoostingSpanScorer((TermSpans) query
057: .getSpans(reader), this , similarity, reader
058: .norms(query.getField()));
059: }
060:
061: class BoostingSpanScorer extends SpanScorer {
062:
063: //TODO: is this the best way to allocate this?
064: byte[] payload = new byte[4];
065: private TermPositions positions;
066: protected float payloadScore;
067: private int payloadsSeen;
068:
069: public BoostingSpanScorer(TermSpans spans, Weight weight,
070: Similarity similarity, byte[] norms)
071: throws IOException {
072: super (spans, weight, similarity, norms);
073: positions = spans.getPositions();
074:
075: }
076:
077: protected boolean setFreqCurrentDoc() throws IOException {
078: if (!more) {
079: return false;
080: }
081: doc = spans.doc();
082: freq = 0.0f;
083: payloadScore = 0;
084: payloadsSeen = 0;
085: Similarity similarity1 = getSimilarity();
086: while (more && doc == spans.doc()) {
087: int matchLength = spans.end() - spans.start();
088:
089: freq += similarity1.sloppyFreq(matchLength);
090: processPayload(similarity1);
091:
092: more = spans.next();//this moves positions to the next match in this document
093: }
094: return more || (freq != 0);
095: }
096:
097: protected void processPayload(Similarity similarity)
098: throws IOException {
099: if (positions.isPayloadAvailable()) {
100: payload = positions.getPayload(payload, 0);
101: payloadScore += AllBoostUtils.readFloat(payload);
102: payloadsSeen++;
103:
104: } else {
105: //zero out the payload?
106: }
107:
108: }
109:
110: public float score() throws IOException {
111:
112: return super .score()
113: * (payloadsSeen > 0 ? (payloadScore / payloadsSeen)
114: : 1);
115: }
116:
117: public Explanation explain(final int doc)
118: throws IOException {
119: Explanation result = new Explanation();
120: Explanation nonPayloadExpl = super .explain(doc);
121: result.addDetail(nonPayloadExpl);
122: //QUESTION: Is there a wau to avoid this skipTo call? We need to know whether to load the payload or not
123:
124: Explanation payloadBoost = new Explanation();
125: result.addDetail(payloadBoost);
126: /*
127: if (skipTo(doc) == true) {
128: processPayload();
129: }
130: */
131:
132: float avgPayloadScore = (payloadsSeen > 0 ? (payloadScore / payloadsSeen)
133: : 1);
134: payloadBoost.setValue(avgPayloadScore);
135: //GSI: I suppose we could toString the payload, but I don't think that would be a good idea
136: payloadBoost.setDescription("scorePayload(...)");
137: result.setValue(nonPayloadExpl.getValue()
138: * avgPayloadScore);
139: result.setDescription("btq, product of:");
140: return result;
141: }
142: }
143:
144: }
145:
146: public boolean equals(Object o) {
147: if (!(o instanceof AllBoostingTermQuery))
148: return false;
149: AllBoostingTermQuery other = (AllBoostingTermQuery) o;
150: return (this.getBoost() == other.getBoost())
151: && this.term.equals(other.term);
152: }
153: }
|