LUCENE-6531: Make PhraseQuery immutable.

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1685754 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Adrien Grand 2015-06-16 10:18:40 +00:00
parent 8d8818fea1
commit c397fe7234
56 changed files with 795 additions and 1006 deletions

View File

@ -32,6 +32,9 @@ API Changes
* LUCENE-6067: Accountable.getChildResources has a default
implementation returning the empty list. (Robert Muir)
* LUCENE-6531: PhraseQuery is now immutable and can be built using the
PhraseQuery.Builder class. (Adrien Grand)
======================= Lucene 5.3.0 =======================
New Features

View File

@ -36,7 +36,12 @@ import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.*;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.store.Directory;
/**
@ -98,8 +103,7 @@ public class ShingleAnalyzerWrapperTest extends BaseTokenStreamTestCase {
* This shows how to construct a phrase query containing shingles.
*/
public void testShingleAnalyzerWrapperPhraseQuery() throws Exception {
PhraseQuery q = new PhraseQuery();
PhraseQuery.Builder builder = new PhraseQuery.Builder();
try (TokenStream ts = analyzer.tokenStream("content", "this sentence")) {
int j = -1;
@ -110,11 +114,12 @@ public class ShingleAnalyzerWrapperTest extends BaseTokenStreamTestCase {
while (ts.incrementToken()) {
j += posIncrAtt.getPositionIncrement();
String termText = termAtt.toString();
q.add(new Term("content", termText), j);
builder.add(new Term("content", termText), j);
}
ts.end();
}
PhraseQuery q = builder.build();
ScoreDoc[] hits = searcher.search(q, 1000).scoreDocs;
int[] ranks = new int[] { 0 };
compareRanks(hits, ranks);

View File

@ -50,29 +50,31 @@ public class SimpleSloppyPhraseQueryMaker extends SimpleQueryMaker {
for (int wd=0; wd<words.length-qlen-slop; wd++) {
// ordered
int remainedSlop = slop;
PhraseQuery q = new PhraseQuery();
q.setSlop(slop);
int wind = wd;
PhraseQuery.Builder builder = new PhraseQuery.Builder();
for (int i=0; i<qlen; i++) {
q.add(new Term(DocMaker.BODY_FIELD,words[wind++]));
builder.add(new Term(DocMaker.BODY_FIELD, words[wind++]), i);
if (remainedSlop>0) {
remainedSlop--;
wind++;
}
}
builder.setSlop(slop);
PhraseQuery q = builder.build();
queries.add(q);
// reversed
remainedSlop = slop;
q = new PhraseQuery();
q.setSlop(slop+2*qlen);
wind = wd+qlen+remainedSlop-1;
builder = new PhraseQuery.Builder();
for (int i=0; i<qlen; i++) {
q.add(new Term(DocMaker.BODY_FIELD,words[wind--]));
builder.add(new Term(DocMaker.BODY_FIELD, words[wind--]), i);
if (remainedSlop>0) {
remainedSlop--;
wind--;
}
}
builder.setSlop(slop + 2 * qlen);
q = builder.build();
queries.add(q);
}
}

View File

@ -55,7 +55,7 @@ public class MultiPhraseQuery extends Query {
private int slop = 0;
/** Sets the phrase slop for this query.
* @see PhraseQuery#setSlop(int)
* @see PhraseQuery#getSlop()
*/
public void setSlop(int s) {
if (s < 0) {
@ -70,14 +70,11 @@ public class MultiPhraseQuery extends Query {
public int getSlop() { return slop; }
/** Add a single term at the next position in the phrase.
* @see PhraseQuery#add(Term)
*/
public void add(Term term) { add(new Term[]{term}); }
/** Add multiple terms at the next position in the phrase. Any of the terms
* may match.
*
* @see PhraseQuery#add(Term)
*/
public void add(Term[] terms) {
int position = 0;
@ -89,8 +86,6 @@ public class MultiPhraseQuery extends Query {
/**
* Allows to specify the relative position of terms within the phrase.
*
* @see PhraseQuery#add(Term, int)
*/
public void add(Term[] terms, int position) {
Objects.requireNonNull(terms, "Term array must not be null");

View File

@ -18,6 +18,7 @@ package org.apache.lucene.search;
*/
import java.io.IOException;
import java.util.Objects;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
@ -30,70 +31,93 @@ import org.apache.lucene.index.Term;
* will query "AB/0 BC/1 CD/2" (where term/position).
*
*/
public class NGramPhraseQuery extends PhraseQuery {
public class NGramPhraseQuery extends Query {
private final int n;
private final PhraseQuery phraseQuery;
/**
* Constructor that takes gram size.
* @param n n-gram size
*/
public NGramPhraseQuery(int n){
public NGramPhraseQuery(int n, PhraseQuery query) {
super();
this.n = n;
this.phraseQuery = Objects.requireNonNull(query);
}
@Override
public Query rewrite(IndexReader reader) throws IOException {
if(getSlop() != 0) return super.rewrite(reader);
// check whether optimizable or not
if(n < 2 || // non-overlap n-gram cannot be optimized
getTerms().length < 3) // too short to optimize
return super.rewrite(reader);
final Term[] terms = phraseQuery.getTerms();
final int[] positions = phraseQuery.getPositions();
// check all posIncrement is 1
// if not, cannot optimize
int[] positions = getPositions();
Term[] terms = getTerms();
int prevPosition = positions[0];
for(int i = 1; i < positions.length; i++){
int pos = positions[i];
if(prevPosition + 1 != pos) return super.rewrite(reader);
prevPosition = pos;
}
boolean isOptimizable = phraseQuery.getSlop() == 0
&& n >= 2 // non-overlap n-gram cannot be optimized
&& terms.length >= 3; // short ones can't be optimized
// now create the new optimized phrase query for n-gram
PhraseQuery optimized = new PhraseQuery();
optimized.setBoost(getBoost());
int pos = 0;
final int lastPos = terms.length - 1;
for(int i = 0; i < terms.length; i++){
if(pos % n == 0 || pos >= lastPos){
optimized.add(terms[i], positions[i]);
if (isOptimizable) {
for (int i = 1; i < positions.length; ++i) {
if (positions[i] != positions[i-1] + 1) {
isOptimizable = false;
break;
}
}
pos++;
}
return optimized;
if (isOptimizable == false) {
return phraseQuery.rewrite(reader);
}
PhraseQuery.Builder builder = new PhraseQuery.Builder();
for (int i = 0; i < terms.length; ++i) {
if (i % n == 0 || i == terms.length - 1) {
builder.add(terms[i], i);
}
}
PhraseQuery rewritten = builder.build();
rewritten.setBoost(phraseQuery.getBoost());
return rewritten;
}
/** Returns true iff <code>o</code> is equal to this. */
@Override
public boolean equals(Object o) {
if (!(o instanceof NGramPhraseQuery))
if (super.equals(o) == false) {
return false;
NGramPhraseQuery other = (NGramPhraseQuery)o;
if(this.n != other.n) return false;
return super.equals(other);
}
NGramPhraseQuery other = (NGramPhraseQuery) o;
return n == other.n && phraseQuery.equals(other.phraseQuery);
}
/** Returns a hash code value for this object.*/
@Override
public int hashCode() {
return Float.floatToIntBits(getBoost())
^ getSlop()
^ getTerms().hashCode()
^ getPositions().hashCode()
^ n;
int h = super.hashCode();
h = 31 * h + phraseQuery.hashCode();
h = 31 * h + n;
return h;
}
/** Return the list of terms. */
public Term[] getTerms() {
return phraseQuery.getTerms();
}
/** Return the list of relative positions that each term should appear at. */
public int[] getPositions() {
return phraseQuery.getPositions();
}
@Override
public float getBoost() {
return phraseQuery.getBoost();
}
@Override
public void setBoost(float b) {
phraseQuery.setBoost(b);
}
@Override
public String toString(String field) {
return phraseQuery.toString(field);
}
}

View File

@ -20,14 +20,15 @@ package org.apache.lucene.search;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.apache.lucene.index.PostingsEnum;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexReaderContext;
import org.apache.lucene.index.LeafReader;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.PostingsEnum;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermContext;
import org.apache.lucene.index.TermState;
@ -37,6 +38,7 @@ import org.apache.lucene.search.similarities.Similarity;
import org.apache.lucene.search.similarities.Similarity.SimScorer;
import org.apache.lucene.util.ArrayUtil;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.ToStringUtils;
/** A Query that matches documents containing a particular sequence of terms.
@ -47,127 +49,235 @@ import org.apache.lucene.util.ToStringUtils;
* <b>NOTE</b>: Leading holes don't have any particular meaning for this query
* and will be ignored. For instance this query:
* <pre class="prettyprint">
* PhraseQuery pq = new PhraseQuery();
* pq.add(new Term("body", "one"), 4);
* pq.add(new Term("body", "two"), 5);
* PhraseQuery.Builder builder = new PhraseQuery.Builder();
* builder.add(new Term("body", "one"), 4);
* builder.add(new Term("body", "two"), 5);
* PhraseQuery pq = builder.build();
* </pre>
* is equivalent to the below query:
* <pre class="prettyprint">
* PhraseQuery pq = new PhraseQuery();
* pq.add(new Term("body", "one"), 0);
* pq.add(new Term("body", "two"), 1);
* PhraseQuery.Builder builder = new PhraseQuery.Builder();
* builder.add(new Term("body", "one"), 0);
* builder.add(new Term("body", "two"), 1);
* PhraseQuery pq = builder.build();
* </pre>
*/
public class PhraseQuery extends Query {
private String field;
private ArrayList<Term> terms = new ArrayList<>(4);
private ArrayList<Integer> positions = new ArrayList<>(4);
private int slop = 0;
/** Constructs an empty phrase query. */
public PhraseQuery() {}
/** A builder for phrase queries. */
public static class Builder {
/** Sets the number of other words permitted between words in query phrase.
If zero, then this is an exact phrase search. For larger values this works
like a <code>WITHIN</code> or <code>NEAR</code> operator.
private int slop;
private final List<Term> terms;
private final List<Integer> positions;
<p>The slop is in fact an edit-distance, where the units correspond to
moves of terms in the query phrase out of position. For example, to switch
the order of two words requires two moves (the first move places the words
atop one another), so to permit re-orderings of phrases, the slop must be
at least two.
<p>More exact matches are scored higher than sloppier matches, thus search
results are sorted by exactness.
<p>The slop is zero by default, requiring exact matches.*/
public void setSlop(int s) {
if (s < 0) {
throw new IllegalArgumentException("slop value cannot be negative");
/** Sole constructor. */
public Builder() {
slop = 0;
terms = new ArrayList<>();
positions = new ArrayList<>();
}
slop = s;
/**
* Set the slop.
* @see PhraseQuery#getSlop()
*/
public void setSlop(int slop) {
this.slop = slop;
}
/**
* Adds a term to the end of the query phrase.
* The relative position of the term is the one immediately after the last term added.
*/
public void add(Term term) {
add(term, positions.isEmpty() ? 0 : 1 + positions.get(positions.size() - 1));
}
/**
* Adds a term to the end of the query phrase.
* The relative position of the term within the phrase is specified explicitly.
* This allows e.g. phrases with more than one term at the same position
* or phrases with gaps (e.g. in connection with stopwords).
*
*/
public void add(Term term, int position) {
term = new Term(term.field(), BytesRef.deepCopyOf(term.bytes())); // be defensive
if (position < 0) {
throw new IllegalArgumentException("Positions must be >= 0, got " + position);
}
if (positions.isEmpty() == false) {
final int lastPosition = positions.get(positions.size() - 1);
if (position < lastPosition) {
throw new IllegalArgumentException("Positions must be added in order, got " + position + " after " + lastPosition);
}
}
if (terms.isEmpty() == false && term.field().equals(terms.get(0).field()) == false) {
throw new IllegalArgumentException("All terms must be on the same field, got " + term.field() + " and " + terms.get(0).field());
}
terms.add(term);
positions.add(position);
}
/**
* Build a phrase query based on the terms that have been added.
*/
public PhraseQuery build() {
Term[] terms = this.terms.toArray(new Term[this.terms.size()]);
int[] positions = new int[this.positions.size()];
for (int i = 0; i < positions.length; ++i) {
positions[i] = this.positions.get(i);
}
return new PhraseQuery(slop, terms, positions);
}
}
/** Returns the slop. See setSlop(). */
private final int slop;
private final String field;
private final Term[] terms;
private final int[] positions;
private PhraseQuery(int slop, Term[] terms, int[] positions) {
if (terms.length != positions.length) {
throw new IllegalArgumentException("Must have as many terms as positions");
}
if (slop < 0) {
throw new IllegalArgumentException("Slop must be >= 0, got " + slop);
}
for (int i = 1; i < terms.length; ++i) {
if (terms[i-1].field().equals(terms[i].field()) == false) {
throw new IllegalArgumentException("All terms should have the same field");
}
}
for (int position : positions) {
if (position < 0) {
throw new IllegalArgumentException("Positions must be >= 0, got " + position);
}
}
for (int i = 1; i < positions.length; ++i) {
if (positions[i] < positions[i - 1]) {
throw new IllegalArgumentException("Positions should not go backwards, got "
+ positions[i-1] + " before " + positions[i]);
}
}
this.slop = slop;
this.terms = terms;
this.positions = positions;
this.field = terms.length == 0 ? null : terms[0].field();
}
private static int[] incrementalPositions(int length) {
int[] positions = new int[length];
for (int i = 0; i < length; ++i) {
positions[i] = i;
}
return positions;
}
private static Term[] toTerms(String field, String... termStrings) {
Term[] terms = new Term[termStrings.length];
for (int i = 0; i < terms.length; ++i) {
terms[i] = new Term(field, termStrings[i]);
}
return terms;
}
private static Term[] toTerms(String field, BytesRef... termBytes) {
Term[] terms = new Term[termBytes.length];
for (int i = 0; i < terms.length; ++i) {
terms[i] = new Term(field, BytesRef.deepCopyOf(termBytes[i]));
}
return terms;
}
/**
* Create a phrase query which will match documents that contain the given
* list of terms at consecutive positions in {@code field}, and at a
* maximum edit distance of {@code slop}. For more complicated use-cases,
* use {@link PhraseQuery.Builder}.
* @see #getSlop()
*/
public PhraseQuery(int slop, String field, String... terms) {
this(slop, toTerms(field, terms), incrementalPositions(terms.length));
}
/**
* Create a phrase query which will match documents that contain the given
* list of terms at consecutive positions in {@code field}.
*/
public PhraseQuery(String field, String... terms) {
this(0, field, terms);
}
/**
* Create a phrase query which will match documents that contain the given
* list of terms at consecutive positions in {@code field}, and at a
* maximum edit distance of {@code slop}. For more complicated use-cases,
* use {@link PhraseQuery.Builder}.
* @see #getSlop()
*/
public PhraseQuery(int slop, String field, BytesRef... terms) {
this(slop, toTerms(field, terms), incrementalPositions(terms.length));
}
/**
* Create a phrase query which will match documents that contain the given
* list of terms at consecutive positions in {@code field}.
*/
public PhraseQuery(String field, BytesRef... terms) {
this(0, field, terms);
}
/**
* Return the slop for this {@link PhraseQuery}.
*
* <p>The slop is an edit distance between respective positions of terms as
* defined in this {@link PhraseQuery} and the positions of terms in a
* document.
*
* <p>For instance, when searching for {@code "quick fox"}, it is expected that
* the difference between the positions of {@code fox} and {@code quick} is 1.
* So {@code "a quick brown fox"} would be at an edit distance of 1 since the
* difference of the positions of {@code fox} and {@code quick} is 2.
* Similarly, {@code "the fox is quick"} would be at an edit distance of 3
* since the difference of the positions of {@code fox} and {@code quick} is -2.
* The slop defines the maximum edit distance for a document to match.
*
* <p>More exact matches are scored higher than sloppier matches, thus search
* results are sorted by exactness.
*/
public int getSlop() { return slop; }
/**
* Adds a term to the end of the query phrase.
* The relative position of the term is the one immediately after the last term added.
*/
public void add(Term term) {
int position = 0;
if (positions.size() > 0) {
position = positions.get(positions.size()-1) + 1;
}
add(term, position);
}
/**
* Adds a term to the end of the query phrase.
* The relative position of the term within the phrase is specified explicitly.
* This allows e.g. phrases with more than one term at the same position
* or phrases with gaps (e.g. in connection with stopwords).
*
*/
public void add(Term term, int position) {
Objects.requireNonNull(term, "Term must not be null");
if (positions.size() > 0) {
final int previousPosition = positions.get(positions.size()-1);
if (position < previousPosition) {
throw new IllegalArgumentException("Positions must be added in order. Got position="
+ position + " while previous position was " + previousPosition);
}
} else if (position < 0) {
throw new IllegalArgumentException("Positions must be positive, got " + position);
}
if (terms.size() == 0) {
field = term.field();
} else if (!term.field().equals(field)) {
throw new IllegalArgumentException("All phrase terms must be in the same field: " + term);
}
terms.add(term);
positions.add(Integer.valueOf(position));
}
/** Returns the set of terms in this phrase. */
/** Returns the list of terms in this phrase. */
public Term[] getTerms() {
return terms.toArray(new Term[0]);
return terms;
}
/**
* Returns the relative positions of terms in this phrase.
*/
public int[] getPositions() {
int[] result = new int[positions.size()];
for(int i = 0; i < positions.size(); i++)
result[i] = positions.get(i).intValue();
return result;
return positions;
}
@Override
public Query rewrite(IndexReader reader) throws IOException {
if (terms.isEmpty()) {
if (terms.length == 0) {
BooleanQuery bq = new BooleanQuery();
bq.setBoost(getBoost());
return bq;
} else if (terms.size() == 1) {
TermQuery tq = new TermQuery(terms.get(0));
} else if (terms.length == 1) {
TermQuery tq = new TermQuery(terms[0]);
tq.setBoost(getBoost());
return tq;
} else if (positions.get(0).intValue() != 0) {
// PhraseWeight requires that positions start at 0 so we need to rebase
// positions
final Term[] terms = getTerms();
final int[] positions = getPositions();
PhraseQuery rewritten = new PhraseQuery();
for (int i = 0; i < terms.length; ++i) {
rewritten.add(terms[i], positions[i] - positions[0]);
} else if (positions[0] != 0) {
int[] newPositions = new int[positions.length];
for (int i = 0; i < positions.length; ++i) {
newPositions[i] = positions[i] - positions[0];
}
PhraseQuery rewritten = new PhraseQuery(slop, terms, newPositions);
rewritten.setBoost(getBoost());
rewritten.setSlop(getSlop());
return rewritten;
} else {
return super.rewrite(reader);
@ -257,10 +367,10 @@ public class PhraseQuery extends Query {
this.needsScores = needsScores;
this.similarity = searcher.getSimilarity(needsScores);
final IndexReaderContext context = searcher.getTopReaderContext();
states = new TermContext[terms.size()];
TermStatistics termStats[] = new TermStatistics[terms.size()];
for (int i = 0; i < terms.size(); i++) {
final Term term = terms.get(i);
states = new TermContext[terms.length];
TermStatistics termStats[] = new TermStatistics[terms.length];
for (int i = 0; i < terms.length; i++) {
final Term term = terms[i];
states[i] = TermContext.build(context, term);
termStats[i] = searcher.termStatistics(term, states[i]);
}
@ -269,7 +379,7 @@ public class PhraseQuery extends Query {
@Override
public void extractTerms(Set<Term> queryTerms) {
queryTerms.addAll(terms);
Collections.addAll(queryTerms, terms);
}
@Override
@ -287,10 +397,10 @@ public class PhraseQuery extends Query {
@Override
public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException {
assert !terms.isEmpty();
assert terms.length > 0;
final LeafReader reader = context.reader();
final Bits liveDocs = acceptDocs;
PostingsAndFreq[] postingsFreqs = new PostingsAndFreq[terms.size()];
PostingsAndFreq[] postingsFreqs = new PostingsAndFreq[terms.length];
final Terms fieldTerms = reader.terms(field);
if (fieldTerms == null) {
@ -304,8 +414,8 @@ public class PhraseQuery extends Query {
// Reuse single TermsEnum below:
final TermsEnum te = fieldTerms.iterator();
for (int i = 0; i < terms.size(); i++) {
final Term t = terms.get(i);
for (int i = 0; i < terms.length; i++) {
final Term t = terms[i];
final TermState state = states[i].get(context.ord);
if (state == null) { /* term doesnt exist in this segment */
assert termNotInReader(reader, t): "no termstate found but term exists in reader";
@ -313,7 +423,7 @@ public class PhraseQuery extends Query {
}
te.seekExact(t.bytes(), state);
PostingsEnum postingsEnum = te.postings(liveDocs, null, PostingsEnum.POSITIONS);
postingsFreqs[i] = new PostingsAndFreq(postingsEnum, positions.get(i), t);
postingsFreqs[i] = new PostingsAndFreq(postingsEnum, positions[i], t);
}
// sort by increasing docFreq order
@ -370,19 +480,19 @@ public class PhraseQuery extends Query {
buffer.append("\"");
final int maxPosition;
if (positions.isEmpty()) {
if (positions.length == 0) {
maxPosition = -1;
} else {
maxPosition = positions.get(positions.size() - 1);
maxPosition = positions[positions.length - 1];
}
String[] pieces = new String[maxPosition + 1];
for (int i = 0; i < terms.size(); i++) {
int pos = positions.get(i).intValue();
for (int i = 0; i < terms.length; i++) {
int pos = positions[i];
String s = pieces[pos];
if (s == null) {
s = (terms.get(i)).text();
s = (terms[i]).text();
} else {
s = s + "|" + (terms.get(i)).text();
s = s + "|" + (terms[i]).text();
}
pieces[pos] = s;
}
@ -412,22 +522,23 @@ public class PhraseQuery extends Query {
/** Returns true iff <code>o</code> is equal to this. */
@Override
public boolean equals(Object o) {
if (!(o instanceof PhraseQuery))
if (super.equals(o) == false) {
return false;
PhraseQuery other = (PhraseQuery)o;
return super.equals(o)
&& (this.slop == other.slop)
&& this.terms.equals(other.terms)
&& this.positions.equals(other.positions);
}
PhraseQuery that = (PhraseQuery) o;
return slop == that.slop
&& Arrays.equals(terms, that.terms)
&& Arrays.equals(positions, that.positions);
}
/** Returns a hash code value for this object.*/
@Override
public int hashCode() {
return super.hashCode()
^ slop
^ terms.hashCode()
^ positions.hashCode();
int h = super.hashCode();
h = 31 * h + slop;
h = 31 * h + Arrays.hashCode(terms);
h = 31 * h + Arrays.hashCode(positions);
return h;
}
}

View File

@ -664,7 +664,7 @@ public abstract class TFIDFSimilarity extends Similarity {
* return larger values when the edit distance is small and smaller values
* when it is large.
*
* @see PhraseQuery#setSlop(int)
* @see PhraseQuery#getSlop()
* @param distance the edit distance of this sloppy phrase match
* @return the frequency increment for this match
*/

View File

@ -329,8 +329,8 @@ public class QueryBuilder {
* Creates simple phrase query from the cached tokenstream contents
*/
private Query analyzePhrase(String field, TokenStream stream, int slop) throws IOException {
PhraseQuery pq = newPhraseQuery();
pq.setSlop(slop);
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.setSlop(slop);
TermToBytesRefAttribute termAtt = stream.getAttribute(TermToBytesRefAttribute.class);
BytesRef bytes = termAtt.getBytesRef();
@ -344,13 +344,13 @@ public class QueryBuilder {
if (enablePositionIncrements) {
position += posIncrAtt.getPositionIncrement();
pq.add(new Term(field, BytesRef.deepCopyOf(bytes)), position);
} else {
pq.add(new Term(field, BytesRef.deepCopyOf(bytes)));
position += 1;
}
builder.add(new Term(field, bytes), position);
}
return pq;
return builder.build();
}
/**
@ -414,16 +414,6 @@ public class QueryBuilder {
return new TermQuery(term);
}
/**
* Builds a new PhraseQuery instance.
* <p>
* This is intended for subclasses that wish to customize the generated queries.
* @return new PhraseQuery instance
*/
protected PhraseQuery newPhraseQuery() {
return new PhraseQuery();
}
/**
* Builds a new MultiPhraseQuery instance.
* <p>

View File

@ -70,9 +70,7 @@ public class TestDemo extends LuceneTestCase {
}
// Test simple phrase query
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.add(new Term("fieldname", "to"));
phraseQuery.add(new Term("fieldname", "be"));
PhraseQuery phraseQuery = new PhraseQuery("fieldname", "to", "be");
assertEquals(1, isearcher.search(phraseQuery, 1).totalHits);
ireader.close();

View File

@ -167,15 +167,10 @@ public class TestSearch extends LuceneTestCase {
booleanAB.add(new TermQuery(new Term("contents", "b")), BooleanClause.Occur.SHOULD);
queries.add(booleanAB);
PhraseQuery phraseAB = new PhraseQuery();
phraseAB.add(new Term("contents", "a"));
phraseAB.add(new Term("contents", "b"));
PhraseQuery phraseAB = new PhraseQuery("contents", "a", "b");
queries.add(phraseAB);
PhraseQuery phraseABC = new PhraseQuery();
phraseABC.add(new Term("contents", "a"));
phraseABC.add(new Term("contents", "b"));
phraseABC.add(new Term("contents", "c"));
PhraseQuery phraseABC = new PhraseQuery("contents", "a", "b", "c");
queries.add(phraseABC);
BooleanQuery booleanAC = new BooleanQuery();
@ -183,15 +178,10 @@ public class TestSearch extends LuceneTestCase {
booleanAC.add(new TermQuery(new Term("contents", "c")), BooleanClause.Occur.SHOULD);
queries.add(booleanAC);
PhraseQuery phraseAC = new PhraseQuery();
phraseAC.add(new Term("contents", "a"));
phraseAC.add(new Term("contents", "c"));
PhraseQuery phraseAC = new PhraseQuery("contents", "a", "c");
queries.add(phraseAC);
PhraseQuery phraseACE = new PhraseQuery();
phraseACE.add(new Term("contents", "a"));
phraseACE.add(new Term("contents", "c"));
phraseACE.add(new Term("contents", "e"));
PhraseQuery phraseACE = new PhraseQuery("contents", "a", "c", "e");
queries.add(phraseACE);
return queries;

View File

@ -246,9 +246,7 @@ public class TestDocument extends LuceneTestCase {
IndexReader reader = writer.getReader();
IndexSearcher searcher = newSearcher(reader);
PhraseQuery query = new PhraseQuery();
query.add(new Term("indexed_not_tokenized", "test1"));
query.add(new Term("indexed_not_tokenized", "test2"));
PhraseQuery query = new PhraseQuery("indexed_not_tokenized", "test1", "test2");
ScoreDoc[] hits = searcher.search(query, 1000).scoreDocs;
assertEquals(1, hits.length);

View File

@ -172,9 +172,7 @@ public class TestAddIndexes extends LuceneTestCase {
writer.updateDocument(new Term("id", "" + (i%10)), doc);
}
// Deletes one of the 10 added docs, leaving 9:
PhraseQuery q = new PhraseQuery();
q.add(new Term("content", "bbb"));
q.add(new Term("content", "14"));
PhraseQuery q = new PhraseQuery("content", "bbb", "14");
writer.deleteDocuments(q);
writer.forceMerge(1);
@ -210,9 +208,7 @@ public class TestAddIndexes extends LuceneTestCase {
writer.addIndexes(aux);
// Deletes one of the 10 added docs, leaving 9:
PhraseQuery q = new PhraseQuery();
q.add(new Term("content", "bbb"));
q.add(new Term("content", "14"));
PhraseQuery q = new PhraseQuery("content", "bbb", "14");
writer.deleteDocuments(q);
writer.forceMerge(1);
@ -246,9 +242,7 @@ public class TestAddIndexes extends LuceneTestCase {
}
// Deletes one of the 10 added docs, leaving 9:
PhraseQuery q = new PhraseQuery();
q.add(new Term("content", "bbb"));
q.add(new Term("content", "14"));
PhraseQuery q = new PhraseQuery("content", "bbb", "14");
writer.deleteDocuments(q);
writer.addIndexes(aux);

View File

@ -1894,9 +1894,10 @@ public class TestIndexWriter extends LuceneTestCase {
IndexReader ir = iw.getReader();
iw.close();
IndexSearcher is = newSearcher(ir);
PhraseQuery pq = new PhraseQuery();
pq.add(new Term("body", "just"), 0);
pq.add(new Term("body", "test"), 2);
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.add(new Term("body", "just"), 0);
builder.add(new Term("body", "test"), 2);
PhraseQuery pq = builder.build();
// body:"just ? test"
assertEquals(1, is.search(pq, 5).totalHits);
ir.close();
@ -1925,9 +1926,10 @@ public class TestIndexWriter extends LuceneTestCase {
IndexReader ir = iw.getReader();
iw.close();
IndexSearcher is = newSearcher(ir);
PhraseQuery pq = new PhraseQuery();
pq.add(new Term("body", "just"), 0);
pq.add(new Term("body", "test"), 3);
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.add(new Term("body", "just"), 0);
builder.add(new Term("body", "test"), 3);
PhraseQuery pq = builder.build();
// body:"just ? ? test"
assertEquals(1, is.search(pq, 5).totalHits);
ir.close();

View File

@ -1410,14 +1410,10 @@ public class TestIndexWriterExceptions extends LuceneTestCase {
w.close();
final IndexSearcher s = newSearcher(r);
PhraseQuery pq = new PhraseQuery();
pq.add(new Term("content", "silly"));
pq.add(new Term("content", "content"));
PhraseQuery pq = new PhraseQuery("content", "silly", "good");
assertEquals(0, s.search(pq, 1).totalHits);
pq = new PhraseQuery();
pq.add(new Term("content", "good"));
pq.add(new Term("content", "content"));
pq = new PhraseQuery("content", "good", "content");
assertEquals(numDocs1+numDocs2, s.search(pq, 1).totalHits);
r.close();
dir.close();
@ -1491,14 +1487,10 @@ public class TestIndexWriterExceptions extends LuceneTestCase {
w.close();
final IndexSearcher s = newSearcher(r);
PhraseQuery pq = new PhraseQuery();
pq.add(new Term("content", "silly"));
pq.add(new Term("content", "content"));
PhraseQuery pq = new PhraseQuery("content", "silly", "content");
assertEquals(numDocs2, s.search(pq, 1).totalHits);
pq = new PhraseQuery();
pq.add(new Term("content", "good"));
pq.add(new Term("content", "content"));
pq = new PhraseQuery("content", "good", "content");
assertEquals(numDocs1+numDocs3+numDocs4, s.search(pq, 1).totalHits);
r.close();
dir.close();

View File

@ -111,9 +111,7 @@ public class TestLazyProxSkipping extends LuceneTestCase {
private ScoreDoc[] search() throws IOException {
// create PhraseQuery "term1 term2" and search
PhraseQuery pq = new PhraseQuery();
pq.add(new Term(this.field, this.term1));
pq.add(new Term(this.field, this.term2));
PhraseQuery pq = new PhraseQuery(field, term1, term2);
return this.searcher.search(pq, 1000).scoreDocs;
}

View File

@ -308,9 +308,7 @@ public class TestOmitTf extends LuceneTestCase {
TermQuery q3 = new TermQuery(c);
TermQuery q4 = new TermQuery(d);
PhraseQuery pq = new PhraseQuery();
pq.add(a);
pq.add(c);
PhraseQuery pq = new PhraseQuery(a.field(), a.bytes(), c.bytes());
try {
searcher.search(pq, 10);
fail("did not hit expected exception");

View File

@ -31,6 +31,7 @@ import org.apache.lucene.search.similarities.DefaultSimilarity;
import org.apache.lucene.search.similarities.Similarity;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.MockDirectoryWrapper;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.TestUtil;
import org.junit.AfterClass;
@ -332,13 +333,9 @@ public class TestBoolean2 extends LuceneTestCase {
if (qType < 3) {
q = new TermQuery(new Term(field, vals[rnd.nextInt(vals.length)]));
} else if (qType < 4) {
Term t1 = new Term(field, vals[rnd.nextInt(vals.length)]);
Term t2 = new Term(field, vals[rnd.nextInt(vals.length)]);
PhraseQuery pq = new PhraseQuery();
pq.add(t1);
pq.add(t2);
pq.setSlop(10); // increase possibility of matching
q = pq;
String t1 = vals[rnd.nextInt(vals.length)];
String t2 = vals[rnd.nextInt(vals.length)];
q = new PhraseQuery(10, field, t1, t2); // slop increases possibility of matching
} else if (qType < 7) {
q = new WildcardQuery(new Term(field, "w*"));
} else {

View File

@ -110,9 +110,7 @@ public class TestBooleanQuery extends LuceneTestCase {
// LUCENE-2617: make sure that a clause not in the index still contributes to the score via coord factor
BooleanQuery qq = q.clone();
PhraseQuery phrase = new PhraseQuery();
phrase.add(new Term("field", "not_in_index"));
phrase.add(new Term("field", "another_not_in_index"));
PhraseQuery phrase = new PhraseQuery("field", "not_in_index", "another_not_in_index");
phrase.setBoost(0);
qq.add(phrase, BooleanClause.Occur.SHOULD);
score2 = s.search(qq, 10).getMaxScore();
@ -126,14 +124,14 @@ public class TestBooleanQuery extends LuceneTestCase {
assertEquals(score*(2/3F), score2, 1e-6);
// PhraseQuery w/ no terms added returns a null scorer
PhraseQuery pq = new PhraseQuery();
PhraseQuery pq = new PhraseQuery("field", new String[0]);
q.add(pq, BooleanClause.Occur.SHOULD);
assertEquals(1, s.search(q, 10).totalHits);
// A required clause which returns null scorer should return null scorer to
// IndexSearcher.
q = new BooleanQuery();
pq = new PhraseQuery();
pq = new PhraseQuery("field", new String[0]);
q.add(new TermQuery(new Term("field", "a")), BooleanClause.Occur.SHOULD);
q.add(pq, BooleanClause.Occur.MUST);
assertEquals(0, s.search(q, 10).totalHits);
@ -610,9 +608,7 @@ public class TestBooleanQuery extends LuceneTestCase {
final IndexSearcher searcher = new IndexSearcher(reader);
searcher.setQueryCache(null); // to still have approximations
PhraseQuery pq = new PhraseQuery();
pq.add(new Term("field", "a"));
pq.add(new Term("field", "b"));
PhraseQuery pq = new PhraseQuery("field", "a", "b");
BooleanQuery q = new BooleanQuery();
q.add(pq, Occur.MUST);
@ -641,9 +637,7 @@ public class TestBooleanQuery extends LuceneTestCase {
final IndexSearcher searcher = new IndexSearcher(reader);
searcher.setQueryCache(null); // to still have approximations
PhraseQuery pq = new PhraseQuery();
pq.add(new Term("field", "a"));
pq.add(new Term("field", "b"));
PhraseQuery pq = new PhraseQuery("field", "a", "b");
BooleanQuery q = new BooleanQuery();
q.add(pq, Occur.SHOULD);
@ -674,9 +668,7 @@ public class TestBooleanQuery extends LuceneTestCase {
final IndexSearcher searcher = new IndexSearcher(reader);
searcher.setQueryCache(null); // to still have approximations
PhraseQuery pq = new PhraseQuery();
pq.add(new Term("field", "a"));
pq.add(new Term("field", "b"));
PhraseQuery pq = new PhraseQuery("field", "a", "b");
BooleanQuery q = new BooleanQuery();
q.add(pq, Occur.SHOULD);
@ -705,9 +697,7 @@ public class TestBooleanQuery extends LuceneTestCase {
final IndexSearcher searcher = new IndexSearcher(reader);
searcher.setQueryCache(null); // to still have approximations
PhraseQuery pq = new PhraseQuery();
pq.add(new Term("field", "a"));
pq.add(new Term("field", "b"));
PhraseQuery pq = new PhraseQuery("field", "a", "b");
BooleanQuery q = new BooleanQuery();
q.add(pq, Occur.SHOULD);
@ -736,9 +726,7 @@ public class TestBooleanQuery extends LuceneTestCase {
final IndexSearcher searcher = new IndexSearcher(reader);
searcher.setQueryCache(null); // to still have approximations
PhraseQuery pq = new PhraseQuery();
pq.add(new Term("field", "a"));
pq.add(new Term("field", "b"));
PhraseQuery pq = new PhraseQuery("field", "a", "b");
BooleanQuery q = new BooleanQuery();
q.add(pq, Occur.MUST);

View File

@ -60,10 +60,7 @@ public class TestComplexExplanations extends BaseExplanationTestCase {
BooleanQuery q = new BooleanQuery();
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.setSlop(1);
phraseQuery.add(new Term(FIELD, "w1"));
phraseQuery.add(new Term(FIELD, "w2"));
PhraseQuery phraseQuery = new PhraseQuery(1, FIELD, "w1", "w2");
q.add(phraseQuery, Occur.MUST);
q.add(snear(st("w2"),
sor("w5","zz"),
@ -123,10 +120,7 @@ public class TestComplexExplanations extends BaseExplanationTestCase {
BooleanQuery q = new BooleanQuery();
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.setSlop(1);
phraseQuery.add(new Term(FIELD, "w1"));
phraseQuery.add(new Term(FIELD, "w2"));
PhraseQuery phraseQuery = new PhraseQuery(1, FIELD, "w1", "w2");
q.add(phraseQuery, Occur.MUST);
q.add(snear(st("w2"),
sor("w5","zz"),

View File

@ -231,9 +231,7 @@ public class TestConstantScoreQuery extends LuceneTestCase {
final IndexSearcher searcher = newSearcher(reader);
searcher.setQueryCache(null); // to still have approximations
PhraseQuery pq = new PhraseQuery();
pq.add(new Term("field", "a"));
pq.add(new Term("field", "b"));
PhraseQuery pq = new PhraseQuery("field", "a", "b");
ConstantScoreQuery q = new ConstantScoreQuery(pq);

View File

@ -850,10 +850,9 @@ public class TestLRUQueryCache extends LuceneTestCase {
bq.setMinimumNumberShouldMatch(TestUtil.nextInt(random(), 0, numShould));
return bq;
case 2:
PhraseQuery pq = new PhraseQuery();
pq.add(randomTerm());
pq.add(randomTerm());
pq.setSlop(random().nextInt(2));
Term t1 = randomTerm();
Term t2 = randomTerm();
PhraseQuery pq = new PhraseQuery(random().nextInt(2), t1.field(), t1.bytes(), t2.bytes());
return pq;
case 3:
return new MatchAllDocsQuery();

View File

@ -496,17 +496,18 @@ public class TestMultiPhraseQuery extends LuceneTestCase {
* PQ AND Mode - Manually creating a phrase query
*/
public void testZeroPosIncrSloppyPqAnd() throws IOException {
final PhraseQuery pq = new PhraseQuery();
PhraseQuery.Builder builder = new PhraseQuery.Builder();
int pos = -1;
for (Token tap : INCR_0_QUERY_TOKENS_AND) {
pos += tap.getPositionIncrement();
pq.add(new Term("field",tap.toString()), pos);
builder.add(new Term("field", tap.toString()), pos);
}
doTestZeroPosIncrSloppy(pq, 0);
pq.setSlop(1);
doTestZeroPosIncrSloppy(pq, 0);
pq.setSlop(2);
doTestZeroPosIncrSloppy(pq, 1);
builder.setSlop(0);
doTestZeroPosIncrSloppy(builder.build(), 0);
builder.setSlop(1);
doTestZeroPosIncrSloppy(builder.build(), 0);
builder.setSlop(2);
doTestZeroPosIncrSloppy(builder.build(), 1);
}
/**

View File

@ -49,51 +49,36 @@ public class TestNGramPhraseQuery extends LuceneTestCase {
public void testRewrite() throws Exception {
// bi-gram test ABC => AB/BC => AB/BC
PhraseQuery pq1 = new NGramPhraseQuery(2);
pq1.add(new Term("f", "AB"));
pq1.add(new Term("f", "BC"));
NGramPhraseQuery pq1 = new NGramPhraseQuery(2, new PhraseQuery("f", "AB", "BC"));
Query q = pq1.rewrite(reader);
assertTrue(q instanceof NGramPhraseQuery);
assertSame(pq1, q);
pq1 = (NGramPhraseQuery)q;
assertArrayEquals(new Term[]{new Term("f", "AB"), new Term("f", "BC")}, pq1.getTerms());
assertArrayEquals(new int[]{0, 1}, pq1.getPositions());
assertSame(q.rewrite(reader), q);
PhraseQuery rewritten1 = (PhraseQuery) q;
assertArrayEquals(new Term[]{new Term("f", "AB"), new Term("f", "BC")}, rewritten1.getTerms());
assertArrayEquals(new int[]{0, 1}, rewritten1.getPositions());
// bi-gram test ABCD => AB/BC/CD => AB//CD
PhraseQuery pq2 = new NGramPhraseQuery(2);
pq2.add(new Term("f", "AB"));
pq2.add(new Term("f", "BC"));
pq2.add(new Term("f", "CD"));
NGramPhraseQuery pq2 = new NGramPhraseQuery(2, new PhraseQuery("f", "AB", "BC", "CD"));
q = pq2.rewrite(reader);
assertTrue(q instanceof PhraseQuery);
assertNotSame(pq2, q);
pq2 = (PhraseQuery)q;
assertArrayEquals(new Term[]{new Term("f", "AB"), new Term("f", "CD")}, pq2.getTerms());
assertArrayEquals(new int[]{0, 2}, pq2.getPositions());
PhraseQuery rewritten2 = (PhraseQuery) q;
assertArrayEquals(new Term[]{new Term("f", "AB"), new Term("f", "CD")}, rewritten2.getTerms());
assertArrayEquals(new int[]{0, 2}, rewritten2.getPositions());
// tri-gram test ABCDEFGH => ABC/BCD/CDE/DEF/EFG/FGH => ABC///DEF//FGH
PhraseQuery pq3 = new NGramPhraseQuery(3);
pq3.add(new Term("f", "ABC"));
pq3.add(new Term("f", "BCD"));
pq3.add(new Term("f", "CDE"));
pq3.add(new Term("f", "DEF"));
pq3.add(new Term("f", "EFG"));
pq3.add(new Term("f", "FGH"));
NGramPhraseQuery pq3 = new NGramPhraseQuery(3, new PhraseQuery("f", "ABC", "BCD", "CDE", "DEF", "EFG", "FGH"));
q = pq3.rewrite(reader);
assertTrue(q instanceof PhraseQuery);
assertNotSame(pq3, q);
pq3 = (PhraseQuery)q;
assertArrayEquals(new Term[]{new Term("f", "ABC"), new Term("f", "DEF"), new Term("f", "FGH")}, pq3.getTerms());
assertArrayEquals(new int[]{0, 3, 5}, pq3.getPositions());
PhraseQuery rewritten3 = (PhraseQuery) q;
assertArrayEquals(new Term[]{new Term("f", "ABC"), new Term("f", "DEF"), new Term("f", "FGH")}, rewritten3.getTerms());
assertArrayEquals(new int[]{0, 3, 5}, rewritten3.getPositions());
// LUCENE-4970: boosting test
PhraseQuery pq4 = new NGramPhraseQuery(2);
pq4.add(new Term("f", "AB"));
pq4.add(new Term("f", "BC"));
pq4.add(new Term("f", "CD"));
NGramPhraseQuery pq4 = new NGramPhraseQuery(2, new PhraseQuery("f", "AB", "BC", "CD"));
pq4.setBoost(100.0F);
q = pq4.rewrite(reader);

View File

@ -97,7 +97,6 @@ public class TestPhraseQuery extends LuceneTestCase {
@Override
public void setUp() throws Exception {
super.setUp();
query = new PhraseQuery();
}
@AfterClass
@ -110,18 +109,14 @@ public class TestPhraseQuery extends LuceneTestCase {
}
public void testNotCloseEnough() throws Exception {
query.setSlop(2);
query.add(new Term("field", "one"));
query.add(new Term("field", "five"));
query = new PhraseQuery(2, "field", "one", "five");
ScoreDoc[] hits = searcher.search(query, 1000).scoreDocs;
assertEquals(0, hits.length);
QueryUtils.check(random(), query,searcher);
}
public void testBarelyCloseEnough() throws Exception {
query.setSlop(3);
query.add(new Term("field", "one"));
query.add(new Term("field", "five"));
query = new PhraseQuery(3, "field", "one", "five");
ScoreDoc[] hits = searcher.search(query, 1000).scoreDocs;
assertEquals(1, hits.length);
QueryUtils.check(random(), query,searcher);
@ -132,16 +127,13 @@ public class TestPhraseQuery extends LuceneTestCase {
*/
public void testExact() throws Exception {
// slop is zero by default
query.add(new Term("field", "four"));
query.add(new Term("field", "five"));
query = new PhraseQuery("field", "four", "five");
ScoreDoc[] hits = searcher.search(query, 1000).scoreDocs;
assertEquals("exact match", 1, hits.length);
QueryUtils.check(random(), query,searcher);
query = new PhraseQuery();
query.add(new Term("field", "two"));
query.add(new Term("field", "one"));
query = new PhraseQuery("field", "two", "one");
hits = searcher.search(query, 1000).scoreDocs;
assertEquals("reverse not exact", 0, hits.length);
QueryUtils.check(random(), query,searcher);
@ -149,9 +141,7 @@ public class TestPhraseQuery extends LuceneTestCase {
public void testSlop1() throws Exception {
// Ensures slop of 1 works with terms in order.
query.setSlop(1);
query.add(new Term("field", "one"));
query.add(new Term("field", "two"));
query = new PhraseQuery(1, "field", "one", "two");
ScoreDoc[] hits = searcher.search(query, 1000).scoreDocs;
assertEquals("in order", 1, hits.length);
QueryUtils.check(random(), query,searcher);
@ -159,10 +149,7 @@ public class TestPhraseQuery extends LuceneTestCase {
// Ensures slop of 1 does not work for phrases out of order;
// must be at least 2.
query = new PhraseQuery();
query.setSlop(1);
query.add(new Term("field", "two"));
query.add(new Term("field", "one"));
query = new PhraseQuery(1, "field", "two", "one");
hits = searcher.search(query, 1000).scoreDocs;
assertEquals("reversed, slop not 2 or more", 0, hits.length);
QueryUtils.check(random(), query,searcher);
@ -172,18 +159,14 @@ public class TestPhraseQuery extends LuceneTestCase {
* As long as slop is at least 2, terms can be reversed
*/
public void testOrderDoesntMatter() throws Exception {
query.setSlop(2); // must be at least two for reverse order match
query.add(new Term("field", "two"));
query.add(new Term("field", "one"));
// must be at least two for reverse order match
query = new PhraseQuery(2, "field", "two", "one");
ScoreDoc[] hits = searcher.search(query, 1000).scoreDocs;
assertEquals("just sloppy enough", 1, hits.length);
QueryUtils.check(random(), query,searcher);
query = new PhraseQuery();
query.setSlop(2);
query.add(new Term("field", "three"));
query.add(new Term("field", "one"));
query = new PhraseQuery(2, "field", "three", "one");
hits = searcher.search(query, 1000).scoreDocs;
assertEquals("not sloppy enough", 0, hits.length);
QueryUtils.check(random(), query,searcher);
@ -195,26 +178,19 @@ public class TestPhraseQuery extends LuceneTestCase {
* to line up a phrase
*/
public void testMultipleTerms() throws Exception {
query.setSlop(2);
query.add(new Term("field", "one"));
query.add(new Term("field", "three"));
query.add(new Term("field", "five"));
query = new PhraseQuery(2, "field", "one", "three", "five");
ScoreDoc[] hits = searcher.search(query, 1000).scoreDocs;
assertEquals("two total moves", 1, hits.length);
QueryUtils.check(random(), query,searcher);
query = new PhraseQuery();
query.setSlop(5); // it takes six moves to match this phrase
query.add(new Term("field", "five"));
query.add(new Term("field", "three"));
query.add(new Term("field", "one"));
// it takes six moves to match this phrase
query = new PhraseQuery(5, "field", "five", "three", "one");
hits = searcher.search(query, 1000).scoreDocs;
assertEquals("slop of 5 not close enough", 0, hits.length);
QueryUtils.check(random(), query,searcher);
query.setSlop(6);
query = new PhraseQuery(6, "field", "five", "three", "one");
hits = searcher.search(query, 1000).scoreDocs;
assertEquals("slop of 6 just right", 1, hits.length);
QueryUtils.check(random(), query,searcher);
@ -235,9 +211,7 @@ public class TestPhraseQuery extends LuceneTestCase {
IndexSearcher searcher = newSearcher(reader);
// valid exact phrase query
PhraseQuery query = new PhraseQuery();
query.add(new Term("field","stop"));
query.add(new Term("field","words"));
PhraseQuery query = new PhraseQuery("field", "stop", "words");
ScoreDoc[] hits = searcher.search(query, 1000).scoreDocs;
assertEquals(1, hits.length);
QueryUtils.check(random(), query,searcher);
@ -264,9 +238,7 @@ public class TestPhraseQuery extends LuceneTestCase {
IndexSearcher searcher = newSearcher(reader);
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.add(new Term("source", "marketing"));
phraseQuery.add(new Term("source", "info"));
PhraseQuery phraseQuery = new PhraseQuery("source", "marketing", "info");
ScoreDoc[] hits = searcher.search(phraseQuery, 1000).scoreDocs;
assertEquals(2, hits.length);
QueryUtils.check(random(), phraseQuery,searcher);
@ -303,9 +275,7 @@ public class TestPhraseQuery extends LuceneTestCase {
searcher = newSearcher(reader);
termQuery = new TermQuery(new Term("contents","woo"));
phraseQuery = new PhraseQuery();
phraseQuery.add(new Term("contents","map"));
phraseQuery.add(new Term("contents","entry"));
phraseQuery = new PhraseQuery("contents", "map", "entry");
hits = searcher.search(termQuery, 1000).scoreDocs;
assertEquals(3, hits.length);
@ -355,10 +325,7 @@ public class TestPhraseQuery extends LuceneTestCase {
IndexSearcher searcher = newSearcher(reader);
searcher.setSimilarity(new DefaultSimilarity());
PhraseQuery query = new PhraseQuery();
query.add(new Term("field", "firstname"));
query.add(new Term("field", "lastname"));
query.setSlop(Integer.MAX_VALUE);
PhraseQuery query = new PhraseQuery(Integer.MAX_VALUE, "field", "firstname", "lastname");
ScoreDoc[] hits = searcher.search(query, 1000).scoreDocs;
assertEquals(3, hits.length);
// Make sure that those matches where the terms appear closer to
@ -375,25 +342,35 @@ public class TestPhraseQuery extends LuceneTestCase {
}
public void testToString() throws Exception {
PhraseQuery q = new PhraseQuery();
PhraseQuery q = new PhraseQuery("field", new String[0]);
assertEquals("\"\"", q.toString());
q.add(new Term("field", "hi"), 1);
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.add(new Term("field", "hi"), 1);
q = builder.build();
assertEquals("field:\"? hi\"", q.toString());
q = new PhraseQuery(); // Query "this hi this is a test is"
q.add(new Term("field", "hi"), 1);
q.add(new Term("field", "test"), 5);
builder = new PhraseQuery.Builder();
builder.add(new Term("field", "hi"), 1);
builder.add(new Term("field", "test"), 5);
q = builder.build(); // Query "this hi this is a test is"
assertEquals("field:\"? hi ? ? ? test\"", q.toString());
q = new PhraseQuery();
q.add(new Term("field", "hi"), 1);
q.add(new Term("field", "hello"), 1);
q.add(new Term("field", "test"), 5);
builder = new PhraseQuery.Builder();
builder.add(new Term("field", "hi"), 1);
builder.add(new Term("field", "hello"), 1);
builder.add(new Term("field", "test"), 5);
q = builder.build();
assertEquals("field:\"? hi|hello ? ? ? test\"", q.toString());
q.setSlop(5);
builder = new PhraseQuery.Builder();
builder.add(new Term("field", "hi"), 1);
builder.add(new Term("field", "hello"), 1);
builder.add(new Term("field", "test"), 5);
builder.setSlop(5);
q = builder.build();
assertEquals("field:\"? hi|hello ? ? ? test\"~5", q.toString());
q.setBoost(2);
@ -401,17 +378,13 @@ public class TestPhraseQuery extends LuceneTestCase {
}
public void testWrappedPhrase() throws IOException {
query.add(new Term("repeated", "first"));
query.add(new Term("repeated", "part"));
query.add(new Term("repeated", "second"));
query.add(new Term("repeated", "part"));
query.setSlop(100);
query = new PhraseQuery(100, "repeated", "first", "part", "second", "part");
ScoreDoc[] hits = searcher.search(query, 1000).scoreDocs;
assertEquals("slop of 100 just right", 1, hits.length);
QueryUtils.check(random(), query,searcher);
query.setSlop(99);
query = new PhraseQuery(99, "repeated", "first", "part", "second", "part");
hits = searcher.search(query, 1000).scoreDocs;
assertEquals("slop of 99 not enough", 0, hits.length);
@ -421,44 +394,28 @@ public class TestPhraseQuery extends LuceneTestCase {
// work on two docs like this: "phrase exist notexist exist found"
public void testNonExistingPhrase() throws IOException {
// phrase without repetitions that exists in 2 docs
query.add(new Term("nonexist", "phrase"));
query.add(new Term("nonexist", "notexist"));
query.add(new Term("nonexist", "found"));
query.setSlop(2); // would be found this way
query = new PhraseQuery(2, "nonexist", "phrase", "notexist", "found");
ScoreDoc[] hits = searcher.search(query, 1000).scoreDocs;
assertEquals("phrase without repetitions exists in 2 docs", 2, hits.length);
QueryUtils.check(random(), query,searcher);
// phrase with repetitions that exists in 2 docs
query = new PhraseQuery();
query.add(new Term("nonexist", "phrase"));
query.add(new Term("nonexist", "exist"));
query.add(new Term("nonexist", "exist"));
query.setSlop(1); // would be found
query = new PhraseQuery(1, "nonexist", "phrase", "exist", "exist");
hits = searcher.search(query, 1000).scoreDocs;
assertEquals("phrase with repetitions exists in two docs", 2, hits.length);
QueryUtils.check(random(), query,searcher);
// phrase I with repetitions that does not exist in any doc
query = new PhraseQuery();
query.add(new Term("nonexist", "phrase"));
query.add(new Term("nonexist", "notexist"));
query.add(new Term("nonexist", "phrase"));
query.setSlop(1000); // would not be found no matter how high the slop is
query = new PhraseQuery(1000, "nonexist", "phrase", "notexist", "phrase");
hits = searcher.search(query, 1000).scoreDocs;
assertEquals("nonexisting phrase with repetitions does not exist in any doc", 0, hits.length);
QueryUtils.check(random(), query,searcher);
// phrase II with repetitions that does not exist in any doc
query = new PhraseQuery();
query.add(new Term("nonexist", "phrase"));
query.add(new Term("nonexist", "exist"));
query.add(new Term("nonexist", "exist"));
query.add(new Term("nonexist", "exist"));
query.setSlop(1000); // would not be found no matter how high the slop is
query = new PhraseQuery(1000, "nonexist", "phrase", "exist", "exist", "exist");
hits = searcher.search(query, 1000).scoreDocs;
assertEquals("nonexisting phrase with repetitions does not exist in any doc", 0, hits.length);
@ -478,9 +435,7 @@ public class TestPhraseQuery extends LuceneTestCase {
public void testPalyndrome2() throws Exception {
// search on non palyndrome, find phrase with no slop, using exact phrase scorer
query.setSlop(0); // to use exact phrase scorer
query.add(new Term("field", "two"));
query.add(new Term("field", "three"));
query = new PhraseQuery("field", "two", "three"); // to use exact phrase scorer
ScoreDoc[] hits = searcher.search(query, 1000).scoreDocs;
assertEquals("phrase found with exact phrase scorer", 1, hits.length);
float score0 = hits[0].score;
@ -488,7 +443,7 @@ public class TestPhraseQuery extends LuceneTestCase {
QueryUtils.check(random(), query,searcher);
// search on non palyndrome, find phrase with slop 2, though no slop required here.
query.setSlop(2); // to use sloppy scorer
query = new PhraseQuery("field", "two", "three"); // to use sloppy scorer
hits = searcher.search(query, 1000).scoreDocs;
assertEquals("just sloppy enough", 1, hits.length);
float score1 = hits[0].score;
@ -497,10 +452,7 @@ public class TestPhraseQuery extends LuceneTestCase {
QueryUtils.check(random(), query,searcher);
// search ordered in palyndrome, find it twice
query = new PhraseQuery();
query.setSlop(2); // must be at least two for both ordered and reversed to match
query.add(new Term("palindrome", "two"));
query.add(new Term("palindrome", "three"));
query = new PhraseQuery(2, "palindrome", "two", "three"); // must be at least two for both ordered and reversed to match
hits = searcher.search(query, 1000).scoreDocs;
assertEquals("just sloppy enough", 1, hits.length);
//float score2 = hits[0].score;
@ -511,10 +463,7 @@ public class TestPhraseQuery extends LuceneTestCase {
//assertTrue("ordered scores higher in palindrome",score1+SCORE_COMP_THRESH<score2);
// search reveresed in palyndrome, find it twice
query = new PhraseQuery();
query.setSlop(2); // must be at least two for both ordered and reversed to match
query.add(new Term("palindrome", "three"));
query.add(new Term("palindrome", "two"));
query = new PhraseQuery(2, "palindrome", "three", "two"); // must be at least two for both ordered and reversed to match
hits = searcher.search(query, 1000).scoreDocs;
assertEquals("just sloppy enough", 1, hits.length);
//float score3 = hits[0].score;
@ -538,10 +487,8 @@ public class TestPhraseQuery extends LuceneTestCase {
public void testPalyndrome3() throws Exception {
// search on non palyndrome, find phrase with no slop, using exact phrase scorer
query.setSlop(0); // to use exact phrase scorer
query.add(new Term("field", "one"));
query.add(new Term("field", "two"));
query.add(new Term("field", "three"));
// slop=0 to use exact phrase scorer
query = new PhraseQuery(0, "field", "one", "two", "three");
ScoreDoc[] hits = searcher.search(query, 1000).scoreDocs;
assertEquals("phrase found with exact phrase scorer", 1, hits.length);
float score0 = hits[0].score;
@ -552,7 +499,8 @@ public class TestPhraseQuery extends LuceneTestCase {
searcher.explain(query, 0);
// search on non palyndrome, find phrase with slop 3, though no slop required here.
query.setSlop(4); // to use sloppy scorer
// slop=4 to use sloppy scorer
query = new PhraseQuery(4, "field", "one", "two", "three");
hits = searcher.search(query, 1000).scoreDocs;
assertEquals("just sloppy enough", 1, hits.length);
float score1 = hits[0].score;
@ -561,11 +509,8 @@ public class TestPhraseQuery extends LuceneTestCase {
QueryUtils.check(random(), query,searcher);
// search ordered in palyndrome, find it twice
query = new PhraseQuery();
query.setSlop(4); // must be at least four for both ordered and reversed to match
query.add(new Term("palindrome", "one"));
query.add(new Term("palindrome", "two"));
query.add(new Term("palindrome", "three"));
// slop must be at least four for both ordered and reversed to match
query = new PhraseQuery(4, "palindrome", "one", "two", "three");
hits = searcher.search(query, 1000).scoreDocs;
// just make sure no exc:
@ -580,11 +525,8 @@ public class TestPhraseQuery extends LuceneTestCase {
//assertTrue("ordered scores higher in palindrome",score1+SCORE_COMP_THRESH<score2);
// search reveresed in palyndrome, find it twice
query = new PhraseQuery();
query.setSlop(4); // must be at least four for both ordered and reversed to match
query.add(new Term("palindrome", "three"));
query.add(new Term("palindrome", "two"));
query.add(new Term("palindrome", "one"));
// must be at least four for both ordered and reversed to match
query = new PhraseQuery(4, "palindrome", "three", "two", "one");
hits = searcher.search(query, 1000).scoreDocs;
assertEquals("just sloppy enough", 1, hits.length);
//float score3 = hits[0].score;
@ -599,14 +541,13 @@ public class TestPhraseQuery extends LuceneTestCase {
// LUCENE-1280
public void testEmptyPhraseQuery() throws Throwable {
final BooleanQuery q2 = new BooleanQuery();
q2.add(new PhraseQuery(), BooleanClause.Occur.MUST);
q2.add(new PhraseQuery("field", new String[0]), BooleanClause.Occur.MUST);
q2.toString();
}
/* test that a single term is rewritten to a term query */
public void testRewrite() throws IOException {
PhraseQuery pq = new PhraseQuery();
pq.add(new Term("foo", "bar"));
PhraseQuery pq = new PhraseQuery("foo", "bar");
Query rewritten = pq.rewrite(searcher.getIndexReader());
assertTrue(rewritten instanceof TermQuery);
}
@ -680,12 +621,13 @@ public class TestPhraseQuery extends LuceneTestCase {
final int numTerm = TestUtil.nextInt(r, 2, 20);
final int start = r.nextInt(doc.size()-numTerm);
PhraseQuery pq = new PhraseQuery();
PhraseQuery.Builder builder = new PhraseQuery.Builder();
StringBuilder sb = new StringBuilder();
for(int t=start;t<start+numTerm;t++) {
pq.add(new Term("f", doc.get(t)));
builder.add(new Term("f", doc.get(t)), t);
sb.append(doc.get(t)).append(' ');
}
PhraseQuery pq = builder.build();
TopDocs hits = s.search(pq, NUM_DOCS);
boolean found = false;
@ -704,11 +646,8 @@ public class TestPhraseQuery extends LuceneTestCase {
}
public void testNegativeSlop() throws Exception {
PhraseQuery query = new PhraseQuery();
query.add(new Term("field", "two"));
query.add(new Term("field", "one"));
try {
query.setSlop(-2);
new PhraseQuery(-2, "field", "two", "one");
fail("didn't get expected exception");
} catch (IllegalArgumentException expected) {
// expected exception
@ -716,9 +655,9 @@ public class TestPhraseQuery extends LuceneTestCase {
}
public void testNegativePosition() throws Exception {
PhraseQuery query = new PhraseQuery();
PhraseQuery.Builder builder = new PhraseQuery.Builder();
try {
query.add(new Term("field", "two"), -42);
builder.add(new Term("field", "two"), -42);
fail("didn't get expected exception");
} catch (IllegalArgumentException expected) {
// expected exception
@ -726,11 +665,11 @@ public class TestPhraseQuery extends LuceneTestCase {
}
public void testBackwardPositions() throws Exception {
PhraseQuery query = new PhraseQuery();
query.add(new Term("field", "one"), 1);
query.add(new Term("field", "two"), 5);
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.add(new Term("field", "one"), 1);
builder.add(new Term("field", "two"), 5);
try {
query.add(new Term("field", "three"), 4);
builder.add(new Term("field", "three"), 4);
fail("didn't get expected exception");
} catch (IllegalArgumentException expected) {
// expected exception

View File

@ -123,50 +123,56 @@ public class TestPositionIncrement extends LuceneTestCase {
PhraseQuery q;
ScoreDoc[] hits;
q = new PhraseQuery();
q.add(new Term("field", "1"));
q.add(new Term("field", "2"));
q = new PhraseQuery("field", "1", "2");
hits = searcher.search(q, 1000).scoreDocs;
assertEquals(0, hits.length);
// same as previous, using the builder with implicit positions
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.add(new Term("field", "1"));
builder.add(new Term("field", "2"));
q = builder.build();
hits = searcher.search(q, 1000).scoreDocs;
assertEquals(0, hits.length);
// same as previous, just specify positions explicitely.
q = new PhraseQuery();
q.add(new Term("field", "1"),0);
q.add(new Term("field", "2"),1);
builder = new PhraseQuery.Builder();
builder.add(new Term("field", "1"), 0);
builder.add(new Term("field", "2"), 1);
q = builder.build();
hits = searcher.search(q, 1000).scoreDocs;
assertEquals(0, hits.length);
// specifying correct positions should find the phrase.
q = new PhraseQuery();
q.add(new Term("field", "1"),0);
q.add(new Term("field", "2"),2);
builder = new PhraseQuery.Builder();
builder.add(new Term("field", "1"), 0);
builder.add(new Term("field", "2"), 2);
q = builder.build();
hits = searcher.search(q, 1000).scoreDocs;
assertEquals(1, hits.length);
q = new PhraseQuery();
q.add(new Term("field", "2"));
q.add(new Term("field", "3"));
q = new PhraseQuery("field", "2", "3");
hits = searcher.search(q, 1000).scoreDocs;
assertEquals(1, hits.length);
q = new PhraseQuery();
q.add(new Term("field", "3"));
q.add(new Term("field", "4"));
q = new PhraseQuery("field", "3", "4");
hits = searcher.search(q, 1000).scoreDocs;
assertEquals(0, hits.length);
// phrase query would find it when correct positions are specified.
q = new PhraseQuery();
q.add(new Term("field", "3"),0);
q.add(new Term("field", "4"),0);
builder = new PhraseQuery.Builder();
builder.add(new Term("field", "3"), 0);
builder.add(new Term("field", "4"), 0);
q = builder.build();
hits = searcher.search(q, 1000).scoreDocs;
assertEquals(1, hits.length);
// phrase query should fail for non existing searched term
// even if there exist another searched terms in the same searched position.
q = new PhraseQuery();
q.add(new Term("field", "3"),0);
q.add(new Term("field", "9"),0);
builder = new PhraseQuery.Builder();
builder.add(new Term("field", "3"), 0);
builder.add(new Term("field", "9"), 0);
q = builder.build();
hits = searcher.search(q, 1000).scoreDocs;
assertEquals(0, hits.length);
@ -177,27 +183,19 @@ public class TestPositionIncrement extends LuceneTestCase {
hits = searcher.search(mq, 1000).scoreDocs;
assertEquals(1, hits.length);
q = new PhraseQuery();
q.add(new Term("field", "2"));
q.add(new Term("field", "4"));
q = new PhraseQuery("field", "2", "4");
hits = searcher.search(q, 1000).scoreDocs;
assertEquals(1, hits.length);
q = new PhraseQuery();
q.add(new Term("field", "3"));
q.add(new Term("field", "5"));
q = new PhraseQuery("field", "3", "5");
hits = searcher.search(q, 1000).scoreDocs;
assertEquals(1, hits.length);
q = new PhraseQuery();
q.add(new Term("field", "4"));
q.add(new Term("field", "5"));
q = new PhraseQuery("field", "4", "5");
hits = searcher.search(q, 1000).scoreDocs;
assertEquals(1, hits.length);
q = new PhraseQuery();
q.add(new Term("field", "2"));
q.add(new Term("field", "5"));
q = new PhraseQuery("field", "2", "5");
hits = searcher.search(q, 1000).scoreDocs;
assertEquals(0, hits.length);

View File

@ -79,10 +79,7 @@ public class TestQueryRescorer extends LuceneTestCase {
assertEquals("1", searcher.doc(hits.scoreDocs[1].doc).get("id"));
// Now, resort using PhraseQuery:
PhraseQuery pq = new PhraseQuery();
pq.setSlop(5);
pq.add(new Term("field", "wizard"));
pq.add(new Term("field", "oz"));
PhraseQuery pq = new PhraseQuery(5, "field", "wizard", "oz");
TopDocs hits2 = QueryRescorer.rescore(searcher, hits, pq, 2.0, 10);
@ -176,10 +173,7 @@ public class TestQueryRescorer extends LuceneTestCase {
// Now, resort using PhraseQuery, but with an
// opposite-world combine:
PhraseQuery pq = new PhraseQuery();
pq.setSlop(5);
pq.add(new Term("field", "wizard"));
pq.add(new Term("field", "oz"));
PhraseQuery pq = new PhraseQuery(5, "field", "wizard", "oz");
TopDocs hits2 = new QueryRescorer(pq) {
@Override
@ -229,9 +223,7 @@ public class TestQueryRescorer extends LuceneTestCase {
assertEquals("1", searcher.doc(hits.scoreDocs[1].doc).get("id"));
// Now, resort using PhraseQuery:
PhraseQuery pq = new PhraseQuery();
pq.add(new Term("field", "wizard"));
pq.add(new Term("field", "oz"));
PhraseQuery pq = new PhraseQuery("field", "wizard", "oz");
Rescorer rescorer = new QueryRescorer(pq) {
@Override
@ -306,9 +298,7 @@ public class TestQueryRescorer extends LuceneTestCase {
assertEquals("1", searcher.doc(hits.scoreDocs[1].doc).get("id"));
// Now, resort using PhraseQuery, no slop:
PhraseQuery pq = new PhraseQuery();
pq.add(new Term("field", "wizard"));
pq.add(new Term("field", "oz"));
PhraseQuery pq = new PhraseQuery("field", "wizard", "oz");
TopDocs hits2 = QueryRescorer.rescore(searcher, hits, pq, 2.0, 10);

View File

@ -13,8 +13,8 @@ import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.Term;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.BitDocIdSet;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.FixedBitSet;
import org.apache.lucene.util.LuceneTestCase;
@ -324,12 +324,14 @@ public class TestScorerPerf extends LuceneTestCase {
for (int i=0; i<iter; i++) {
int nClauses = random().nextInt(maxClauses-1)+2; // min 2 clauses
PhraseQuery q = new PhraseQuery();
PhraseQuery.Builder builder = new PhraseQuery.Builder();
for (int j=0; j<nClauses; j++) {
int tnum = random().nextInt(termsInIndex);
q.add(new Term("f",Character.toString((char)(tnum+'A'))), j);
builder.add(new Term("f", Character.toString((char)(tnum+'A'))));
}
q.setSlop(termsInIndex); // this could be random too
// slop could be random too
builder.setSlop(termsInIndex);
PhraseQuery q = builder.build();
CountingHitCollector hc = new CountingHitCollector();
s.search(q, hc);

View File

@ -118,9 +118,7 @@ public class TestSimilarity extends LuceneTestCase {
}
});
PhraseQuery pq = new PhraseQuery();
pq.add(a);
pq.add(c);
PhraseQuery pq = new PhraseQuery(a.field(), a.bytes(), c.bytes());
//System.out.println(pq.toString("field"));
searcher.search(pq,
new SimpleCollector() {
@ -140,7 +138,7 @@ public class TestSimilarity extends LuceneTestCase {
}
});
pq.setSlop(2);
pq = new PhraseQuery(2, a.field(), a.bytes(), c.bytes());
//System.out.println(pq.toString("field"));
searcher.search(pq, new SimpleCollector() {
private Scorer scorer;

View File

@ -54,50 +54,31 @@ public class TestSimpleExplanations extends BaseExplanationTestCase {
/* some simple phrase tests */
public void testP1() throws Exception {
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.add(new Term(FIELD, "w1"));
phraseQuery.add(new Term(FIELD, "w2"));
PhraseQuery phraseQuery = new PhraseQuery(FIELD, "w1", "w2");
qtest(phraseQuery, new int[] { 0 });
}
public void testP2() throws Exception {
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.add(new Term(FIELD, "w1"));
phraseQuery.add(new Term(FIELD, "w3"));
PhraseQuery phraseQuery = new PhraseQuery(FIELD, "w1", "w3");
qtest(phraseQuery, new int[] { 1,3 });
}
public void testP3() throws Exception {
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.setSlop(1);
phraseQuery.add(new Term(FIELD, "w1"));
phraseQuery.add(new Term(FIELD, "w2"));
PhraseQuery phraseQuery = new PhraseQuery(1, FIELD, "w1", "w2");
qtest(phraseQuery, new int[] { 0,1,2 });
}
public void testP4() throws Exception {
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.setSlop(1);
phraseQuery.add(new Term(FIELD, "w2"));
phraseQuery.add(new Term(FIELD, "w3"));
PhraseQuery phraseQuery = new PhraseQuery(1, FIELD, "w2", "w3");
qtest(phraseQuery, new int[] { 0,1,2,3 });
}
public void testP5() throws Exception {
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.setSlop(1);
phraseQuery.add(new Term(FIELD, "w3"));
phraseQuery.add(new Term(FIELD, "w2"));
PhraseQuery phraseQuery = new PhraseQuery(1, FIELD, "w3", "w2");
qtest(phraseQuery, new int[] { 1,3 });
}
public void testP6() throws Exception {
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.setSlop(2);
phraseQuery.add(new Term(FIELD, "w3"));
phraseQuery.add(new Term(FIELD, "w2"));
PhraseQuery phraseQuery = new PhraseQuery(2, FIELD, "w3", "w2");
qtest(phraseQuery, new int[] { 0,1,3 });
}
public void testP7() throws Exception {
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.setSlop(3);
phraseQuery.add(new Term(FIELD, "w3"));
phraseQuery.add(new Term(FIELD, "w2"));
PhraseQuery phraseQuery = new PhraseQuery(3, FIELD, "w3", "w2");
qtest(phraseQuery, new int[] { 0,1,2,3 });
}
@ -657,14 +638,10 @@ public class TestSimpleExplanations extends BaseExplanationTestCase {
public void testMultiFieldBQofPQ1() throws Exception {
BooleanQuery query = new BooleanQuery();
PhraseQuery leftChild = new PhraseQuery();
leftChild.add(new Term(FIELD, "w1"));
leftChild.add(new Term(FIELD, "w2"));
PhraseQuery leftChild = new PhraseQuery(FIELD, "w1", "w2");
query.add(leftChild, BooleanClause.Occur.SHOULD);
PhraseQuery rightChild = new PhraseQuery();
rightChild.add(new Term(ALTFIELD, "w1"));
rightChild.add(new Term(ALTFIELD, "w2"));
PhraseQuery rightChild = new PhraseQuery(ALTFIELD, "w1", "w2");
query.add(rightChild, BooleanClause.Occur.SHOULD);
qtest(query, new int[] { 0 });
@ -672,14 +649,10 @@ public class TestSimpleExplanations extends BaseExplanationTestCase {
public void testMultiFieldBQofPQ2() throws Exception {
BooleanQuery query = new BooleanQuery();
PhraseQuery leftChild = new PhraseQuery();
leftChild.add(new Term(FIELD, "w1"));
leftChild.add(new Term(FIELD, "w3"));
PhraseQuery leftChild = new PhraseQuery(FIELD, "w1", "w3");
query.add(leftChild, BooleanClause.Occur.SHOULD);
PhraseQuery rightChild = new PhraseQuery();
rightChild.add(new Term(ALTFIELD, "w1"));
rightChild.add(new Term(ALTFIELD, "w3"));
PhraseQuery rightChild = new PhraseQuery(ALTFIELD, "w1", "w3");
query.add(rightChild, BooleanClause.Occur.SHOULD);
qtest(query, new int[] { 1,3 });
@ -687,16 +660,10 @@ public class TestSimpleExplanations extends BaseExplanationTestCase {
public void testMultiFieldBQofPQ3() throws Exception {
BooleanQuery query = new BooleanQuery();
PhraseQuery leftChild = new PhraseQuery();
leftChild.setSlop(1);
leftChild.add(new Term(FIELD, "w1"));
leftChild.add(new Term(FIELD, "w2"));
PhraseQuery leftChild = new PhraseQuery(1, FIELD, "w1", "w2");
query.add(leftChild, BooleanClause.Occur.SHOULD);
PhraseQuery rightChild = new PhraseQuery();
rightChild.setSlop(1);
rightChild.add(new Term(ALTFIELD, "w1"));
rightChild.add(new Term(ALTFIELD, "w2"));
PhraseQuery rightChild = new PhraseQuery(1, ALTFIELD, "w1", "w2");
query.add(rightChild, BooleanClause.Occur.SHOULD);
qtest(query, new int[] { 0,1,2 });
@ -704,16 +671,10 @@ public class TestSimpleExplanations extends BaseExplanationTestCase {
public void testMultiFieldBQofPQ4() throws Exception {
BooleanQuery query = new BooleanQuery();
PhraseQuery leftChild = new PhraseQuery();
leftChild.setSlop(1);
leftChild.add(new Term(FIELD, "w2"));
leftChild.add(new Term(FIELD, "w3"));
PhraseQuery leftChild = new PhraseQuery(1, FIELD, "w2", "w3");
query.add(leftChild, BooleanClause.Occur.SHOULD);
PhraseQuery rightChild = new PhraseQuery();
rightChild.setSlop(1);
rightChild.add(new Term(ALTFIELD, "w2"));
rightChild.add(new Term(ALTFIELD, "w3"));
PhraseQuery rightChild = new PhraseQuery(1, ALTFIELD, "w2", "w3");
query.add(rightChild, BooleanClause.Occur.SHOULD);
qtest(query, new int[] { 0,1,2,3 });
@ -721,16 +682,10 @@ public class TestSimpleExplanations extends BaseExplanationTestCase {
public void testMultiFieldBQofPQ5() throws Exception {
BooleanQuery query = new BooleanQuery();
PhraseQuery leftChild = new PhraseQuery();
leftChild.setSlop(1);
leftChild.add(new Term(FIELD, "w3"));
leftChild.add(new Term(FIELD, "w2"));
PhraseQuery leftChild = new PhraseQuery(1, FIELD, "w3", "w2");
query.add(leftChild, BooleanClause.Occur.SHOULD);
PhraseQuery rightChild = new PhraseQuery();
rightChild.setSlop(1);
rightChild.add(new Term(ALTFIELD, "w3"));
rightChild.add(new Term(ALTFIELD, "w2"));
PhraseQuery rightChild = new PhraseQuery(1, ALTFIELD, "w3", "w2");
query.add(rightChild, BooleanClause.Occur.SHOULD);
qtest(query, new int[] { 1,3 });
@ -738,16 +693,10 @@ public class TestSimpleExplanations extends BaseExplanationTestCase {
public void testMultiFieldBQofPQ6() throws Exception {
BooleanQuery query = new BooleanQuery();
PhraseQuery leftChild = new PhraseQuery();
leftChild.setSlop(2);
leftChild.add(new Term(FIELD, "w3"));
leftChild.add(new Term(FIELD, "w2"));
PhraseQuery leftChild = new PhraseQuery(2, FIELD, "w3", "w2");
query.add(leftChild, BooleanClause.Occur.SHOULD);
PhraseQuery rightChild = new PhraseQuery();
rightChild.setSlop(2);
rightChild.add(new Term(ALTFIELD, "w3"));
rightChild.add(new Term(ALTFIELD, "w2"));
PhraseQuery rightChild = new PhraseQuery(2, ALTFIELD, "w3", "w2");
query.add(rightChild, BooleanClause.Occur.SHOULD);
qtest(query, new int[] { 0,1,3 });
@ -755,16 +704,10 @@ public class TestSimpleExplanations extends BaseExplanationTestCase {
public void testMultiFieldBQofPQ7() throws Exception {
BooleanQuery query = new BooleanQuery();
PhraseQuery leftChild = new PhraseQuery();
leftChild.setSlop(3);
leftChild.add(new Term(FIELD, "w3"));
leftChild.add(new Term(FIELD, "w2"));
PhraseQuery leftChild = new PhraseQuery(3, FIELD, "w3", "w2");
query.add(leftChild, BooleanClause.Occur.SHOULD);
PhraseQuery rightChild = new PhraseQuery();
rightChild.setSlop(1);
rightChild.add(new Term(ALTFIELD, "w3"));
rightChild.add(new Term(ALTFIELD, "w2"));
PhraseQuery rightChild = new PhraseQuery(1, ALTFIELD, "w3", "w2");
query.add(rightChild, BooleanClause.Occur.SHOULD);
qtest(query, new int[] { 0,1,2,3 });

View File

@ -92,9 +92,7 @@ public class TestSimpleSearchEquivalence extends SearchEquivalenceTestBase {
public void testExactPhraseVersusBooleanAnd() throws Exception {
Term t1 = randomTerm();
Term t2 = randomTerm();
PhraseQuery q1 = new PhraseQuery();
q1.add(t1);
q1.add(t2);
PhraseQuery q1 = new PhraseQuery(t1.field(), t1.bytes(), t2.bytes());
BooleanQuery q2 = new BooleanQuery();
q2.add(new TermQuery(t1), Occur.MUST);
q2.add(new TermQuery(t2), Occur.MUST);
@ -105,9 +103,10 @@ public class TestSimpleSearchEquivalence extends SearchEquivalenceTestBase {
public void testExactPhraseVersusBooleanAndWithHoles() throws Exception {
Term t1 = randomTerm();
Term t2 = randomTerm();
PhraseQuery q1 = new PhraseQuery();
q1.add(t1);
q1.add(t2, 2);
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.add(t1, 0);
builder.add(t2, 2);
PhraseQuery q1 = builder.build();
BooleanQuery q2 = new BooleanQuery();
q2.add(new TermQuery(t1), Occur.MUST);
q2.add(new TermQuery(t2), Occur.MUST);
@ -118,13 +117,8 @@ public class TestSimpleSearchEquivalence extends SearchEquivalenceTestBase {
public void testPhraseVersusSloppyPhrase() throws Exception {
Term t1 = randomTerm();
Term t2 = randomTerm();
PhraseQuery q1 = new PhraseQuery();
q1.add(t1);
q1.add(t2);
PhraseQuery q2 = new PhraseQuery();
q2.add(t1);
q2.add(t2);
q2.setSlop(1);
PhraseQuery q1 = new PhraseQuery(t1.field(), t1.bytes(), t2.bytes());
PhraseQuery q2 = new PhraseQuery(1, t1.field(), t1.bytes(), t2.bytes());
assertSubsetOf(q1, q2);
}
@ -132,13 +126,12 @@ public class TestSimpleSearchEquivalence extends SearchEquivalenceTestBase {
public void testPhraseVersusSloppyPhraseWithHoles() throws Exception {
Term t1 = randomTerm();
Term t2 = randomTerm();
PhraseQuery q1 = new PhraseQuery();
q1.add(t1);
q1.add(t2, 2);
PhraseQuery q2 = new PhraseQuery();
q2.add(t1);
q2.add(t2, 2);
q2.setSlop(1);
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.add(t1, 0);
builder.add(t2, 2);
PhraseQuery q1 = builder.build();
builder.setSlop(2);
PhraseQuery q2 = builder.build();
assertSubsetOf(q1, q2);
}
@ -146,9 +139,7 @@ public class TestSimpleSearchEquivalence extends SearchEquivalenceTestBase {
public void testExactPhraseVersusMultiPhrase() throws Exception {
Term t1 = randomTerm();
Term t2 = randomTerm();
PhraseQuery q1 = new PhraseQuery();
q1.add(t1);
q1.add(t2);
PhraseQuery q1 = new PhraseQuery(t1.field(), t1.bytes(), t2.bytes());
Term t3 = randomTerm();
MultiPhraseQuery q2 = new MultiPhraseQuery();
q2.add(t1);
@ -160,9 +151,10 @@ public class TestSimpleSearchEquivalence extends SearchEquivalenceTestBase {
public void testExactPhraseVersusMultiPhraseWithHoles() throws Exception {
Term t1 = randomTerm();
Term t2 = randomTerm();
PhraseQuery q1 = new PhraseQuery();
q1.add(t1);
q1.add(t2, 2);
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.add(t1, 0);
builder.add(t2, 2);
PhraseQuery q1 = builder.build();
Term t3 = randomTerm();
MultiPhraseQuery q2 = new MultiPhraseQuery();
q2.add(t1);
@ -179,10 +171,7 @@ public class TestSimpleSearchEquivalence extends SearchEquivalenceTestBase {
do {
t2 = randomTerm();
} while (t1.equals(t2));
PhraseQuery q1 = new PhraseQuery();
q1.add(t1);
q1.add(t2);
q1.setSlop(Integer.MAX_VALUE);
PhraseQuery q1 = new PhraseQuery(Integer.MAX_VALUE, t1.field(), t1.bytes(), t2.bytes());
BooleanQuery q2 = new BooleanQuery();
q2.add(new TermQuery(t1), Occur.MUST);
q2.add(new TermQuery(t2), Occur.MUST);
@ -193,12 +182,11 @@ public class TestSimpleSearchEquivalence extends SearchEquivalenceTestBase {
public void testPhraseRelativePositions() throws Exception {
Term t1 = randomTerm();
Term t2 = randomTerm();
PhraseQuery q1 = new PhraseQuery();
q1.add(t1);
q1.add(t2);
PhraseQuery q2 = new PhraseQuery();
q2.add(t1, 10000);
q2.add(t2, 10001);
PhraseQuery q1 = new PhraseQuery(t1.field(), t1.bytes(), t2.bytes());
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.add(t1, 10000);
builder.add(t2, 10001);
PhraseQuery q2 = builder.build();
assertSameScores(q1, q2);
}
@ -206,14 +194,12 @@ public class TestSimpleSearchEquivalence extends SearchEquivalenceTestBase {
public void testSloppyPhraseRelativePositions() throws Exception {
Term t1 = randomTerm();
Term t2 = randomTerm();
PhraseQuery q1 = new PhraseQuery();
q1.add(t1);
q1.add(t2);
q1.setSlop(2);
PhraseQuery q2 = new PhraseQuery();
q2.add(t1, 10000);
q2.add(t2, 10001);
q2.setSlop(2);
PhraseQuery q1 = new PhraseQuery(2, t1.field(), t1.bytes(), t2.bytes());
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.add(t1, 10000);
builder.add(t2, 10001);
builder.setSlop(2);
PhraseQuery q2 = builder.build();
assertSameScores(q1, q2);
}
}

View File

@ -17,6 +17,8 @@ package org.apache.lucene.search;
* limitations under the License.
*/
import java.io.IOException;
import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.analysis.MockTokenizer;
import org.apache.lucene.document.Document;
@ -31,8 +33,6 @@ import org.apache.lucene.store.MockDirectoryWrapper;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.LuceneTestCase;
import java.io.IOException;
public class TestSloppyPhraseQuery extends LuceneTestCase {
private static final String S_1 = "A A A";
@ -135,7 +135,14 @@ public class TestSloppyPhraseQuery extends LuceneTestCase {
}
private float checkPhraseQuery(Document doc, PhraseQuery query, int slop, int expectedNumResults) throws Exception {
query.setSlop(slop);
PhraseQuery.Builder builder = new PhraseQuery.Builder();
Term[] terms = query.getTerms();
int[] positions = query.getPositions();
for (int i = 0; i < terms.length; ++i) {
builder.add(terms[i], positions[i]);
}
builder.setSlop(slop);
query = builder.build();
MockDirectoryWrapper ramDir = new MockDirectoryWrapper(random(), new RAMDirectory());
RandomIndexWriter writer = new RandomIndexWriter(random(), ramDir, new MockAnalyzer(random(), MockTokenizer.WHITESPACE, false));
@ -168,12 +175,8 @@ public class TestSloppyPhraseQuery extends LuceneTestCase {
}
private static PhraseQuery makePhraseQuery(String terms) {
PhraseQuery query = new PhraseQuery();
String[] t = terms.split(" +");
for (int i=0; i<t.length; i++) {
query.add(new Term("f", t[i]));
}
return query;
return new PhraseQuery("f", t);
}
static class MaxFreqCollector extends SimpleCollector {
@ -242,16 +245,18 @@ public class TestSloppyPhraseQuery extends LuceneTestCase {
IndexReader ir = iw.getReader();
iw.close();
IndexSearcher is = newSearcher(ir);
PhraseQuery pq = new PhraseQuery();
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.add(new Term("lyrics", "drug"), 1);
builder.add(new Term("lyrics", "drug"), 4);
PhraseQuery pq = builder.build();
// "drug the drug"~1
pq.add(new Term("lyrics", "drug"), 1);
pq.add(new Term("lyrics", "drug"), 4);
pq.setSlop(0);
assertEquals(1, is.search(pq, 4).totalHits);
pq.setSlop(1);
builder.setSlop(1);
pq = builder.build();
assertEquals(3, is.search(pq, 4).totalHits);
pq.setSlop(2);
builder.setSlop(2);
pq = builder.build();
assertEquals(4, is.search(pq, 4).totalHits);
ir.close();
dir.close();
@ -270,11 +275,12 @@ public class TestSloppyPhraseQuery extends LuceneTestCase {
iw.close();
IndexSearcher is = newSearcher(ir);
PhraseQuery pq = new PhraseQuery();
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.add(new Term("lyrics", "drug"), 1);
builder.add(new Term("lyrics", "drug"), 3);
builder.setSlop(1);
PhraseQuery pq = builder.build();
// "drug the drug"~1
pq.add(new Term("lyrics", "drug"), 1);
pq.add(new Term("lyrics", "drug"), 3);
pq.setSlop(1);
assertSaneScoring(pq, is);
ir.close();
dir.close();
@ -324,11 +330,12 @@ public class TestSloppyPhraseQuery extends LuceneTestCase {
IndexSearcher is = newSearcher(ir);
PhraseQuery pq = new PhraseQuery();
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.add(new Term("lyrics", "drug"), 1);
builder.add(new Term("lyrics", "drug"), 4);
builder.setSlop(5);
PhraseQuery pq = builder.build();
// "drug the drug"~5
pq.add(new Term("lyrics", "drug"), 1);
pq.add(new Term("lyrics", "drug"), 3);
pq.setSlop(5);
assertSaneScoring(pq, is);
ir.close();
dir.close();

View File

@ -31,15 +31,8 @@ public class TestSloppyPhraseQuery2 extends SearchEquivalenceTestBase {
Term t1 = randomTerm();
Term t2 = randomTerm();
for (int i = 0; i < 10; i++) {
PhraseQuery q1 = new PhraseQuery();
q1.add(t1);
q1.add(t2);
q1.setSlop(i);
PhraseQuery q2 = new PhraseQuery();
q2.add(t1);
q2.add(t2);
q1.setSlop(i);
q2.setSlop(i+1);
PhraseQuery q1 = new PhraseQuery(i, t1.field(), t1.bytes(), t2.bytes());
PhraseQuery q2 = new PhraseQuery(i + 1, t1.field(), t1.bytes(), t2.bytes());
assertSubsetOf(q1, q2);
}
}
@ -49,14 +42,13 @@ public class TestSloppyPhraseQuery2 extends SearchEquivalenceTestBase {
Term t1 = randomTerm();
Term t2 = randomTerm();
for (int i = 0; i < 10; i++) {
PhraseQuery q1 = new PhraseQuery();
q1.add(t1);
q1.add(t2, 2);
q1.setSlop(i);
PhraseQuery q2 = new PhraseQuery();
q2.add(t1);
q2.add(t2, 2);
q2.setSlop(i+1);
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.add(t1, 0);
builder.add(t2, 2);
builder.setSlop(i);
PhraseQuery q1 = builder.build();
builder.setSlop(i + 1);
PhraseQuery q2 = builder.build();
assertSubsetOf(q1, q2);
}
}
@ -67,16 +59,9 @@ public class TestSloppyPhraseQuery2 extends SearchEquivalenceTestBase {
Term t2 = randomTerm();
Term t3 = randomTerm();
for (int i = 0; i < 10; i++) {
PhraseQuery q1 = new PhraseQuery();
q1.add(t1);
q1.add(t2);
q1.add(t3);
q1.setSlop(i);
PhraseQuery q2 = new PhraseQuery();
q2.add(t1);
q2.add(t2);
q2.add(t3);
q2.setSlop(i+1);
PhraseQuery q1 = new PhraseQuery(i, t1.field(), t1.bytes(), t2.bytes(), t3.bytes());
PhraseQuery q2 = new PhraseQuery(i + 1, t1.field(), t1.bytes(), t2.bytes(), t3.bytes());
assertSubsetOf(q1, q2);
assertSubsetOf(q1, q2);
}
}
@ -89,16 +74,14 @@ public class TestSloppyPhraseQuery2 extends SearchEquivalenceTestBase {
int pos1 = 1 + random().nextInt(3);
int pos2 = pos1 + 1 + random().nextInt(3);
for (int i = 0; i < 10; i++) {
PhraseQuery q1 = new PhraseQuery();
q1.add(t1);
q1.add(t2, pos1);
q1.add(t3, pos2);
q1.setSlop(i);
PhraseQuery q2 = new PhraseQuery();
q2.add(t1);
q2.add(t2, pos1);
q2.add(t3, pos2);
q2.setSlop(i+1);
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.add(t1, 0);
builder.add(t2, pos1);
builder.add(t3, pos2);
builder.setSlop(i);
PhraseQuery q1 = builder.build();
builder.setSlop(i + 1);
PhraseQuery q2 = builder.build();
assertSubsetOf(q1, q2);
}
}
@ -107,14 +90,8 @@ public class TestSloppyPhraseQuery2 extends SearchEquivalenceTestBase {
public void testRepetitiveIncreasingSloppiness() throws Exception {
Term t = randomTerm();
for (int i = 0; i < 10; i++) {
PhraseQuery q1 = new PhraseQuery();
q1.add(t);
q1.add(t);
q1.setSlop(i);
PhraseQuery q2 = new PhraseQuery();
q2.add(t);
q2.add(t);
q2.setSlop(i+1);
PhraseQuery q1 = new PhraseQuery(i, t.field(), t.bytes(), t.bytes());
PhraseQuery q2 = new PhraseQuery(i + 1, t.field(), t.bytes(), t.bytes());
assertSubsetOf(q1, q2);
}
}
@ -123,14 +100,13 @@ public class TestSloppyPhraseQuery2 extends SearchEquivalenceTestBase {
public void testRepetitiveIncreasingSloppinessWithHoles() throws Exception {
Term t = randomTerm();
for (int i = 0; i < 10; i++) {
PhraseQuery q1 = new PhraseQuery();
q1.add(t);
q1.add(t, 2);
q1.setSlop(i);
PhraseQuery q2 = new PhraseQuery();
q2.add(t);
q2.add(t, 2);
q2.setSlop(i+1);
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.add(t, 0);
builder.add(t, 2);
builder.setSlop(i);
PhraseQuery q1 = builder.build();
builder.setSlop(i + 1);
PhraseQuery q2 = builder.build();
assertSubsetOf(q1, q2);
}
}
@ -139,16 +115,9 @@ public class TestSloppyPhraseQuery2 extends SearchEquivalenceTestBase {
public void testRepetitiveIncreasingSloppiness3() throws Exception {
Term t = randomTerm();
for (int i = 0; i < 10; i++) {
PhraseQuery q1 = new PhraseQuery();
q1.add(t);
q1.add(t);
q1.add(t);
q1.setSlop(i);
PhraseQuery q2 = new PhraseQuery();
q2.add(t);
q2.add(t);
q2.add(t);
q2.setSlop(i+1);
PhraseQuery q1 = new PhraseQuery(i, t.field(), t.bytes(), t.bytes(), t.bytes());
PhraseQuery q2 = new PhraseQuery(i + 1, t.field(), t.bytes(), t.bytes(), t.bytes());
assertSubsetOf(q1, q2);
assertSubsetOf(q1, q2);
}
}
@ -159,16 +128,15 @@ public class TestSloppyPhraseQuery2 extends SearchEquivalenceTestBase {
int pos1 = 1 + random().nextInt(3);
int pos2 = pos1 + 1 + random().nextInt(3);
for (int i = 0; i < 10; i++) {
PhraseQuery q1 = new PhraseQuery();
q1.add(t);
q1.add(t, pos1);
q1.add(t, pos2);
q1.setSlop(i);
PhraseQuery q2 = new PhraseQuery();
q2.add(t);
q2.add(t, pos1);
q2.add(t, pos2);
q2.setSlop(i+1);
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.add(t, 0);
builder.add(t, pos1);
builder.add(t, pos2);
builder.setSlop(i);
PhraseQuery q1 = builder.build();
builder.setSlop(i + 1);
PhraseQuery q2 = builder.build();
assertSubsetOf(q1, q2);
assertSubsetOf(q1, q2);
}
}

View File

@ -192,9 +192,7 @@ public class TestSubScorerFreqs extends LuceneTestCase {
@Test
public void testPhraseQuery() throws Exception {
PhraseQuery q = new PhraseQuery();
q.add(new Term("f", "b"));
q.add(new Term("f", "c"));
PhraseQuery q = new PhraseQuery("f", "b", "c");
CountingCollector c = new CountingCollector(TopScoreDocCollector.create(10));
s.search(q, c);
final int maxDocs = s.getIndexReader().maxDoc();

View File

@ -113,18 +113,14 @@ public class TestBasics extends LuceneTestCase {
}
public void testPhrase() throws Exception {
PhraseQuery query = new PhraseQuery();
query.add(new Term("field", "seventy"));
query.add(new Term("field", "seven"));
PhraseQuery query = new PhraseQuery("field", "seventy", "seven");
checkHits(query, new int[]
{77, 177, 277, 377, 477, 577, 677, 777, 877,
977, 1077, 1177, 1277, 1377, 1477, 1577, 1677, 1777, 1877, 1977});
}
public void testPhrase2() throws Exception {
PhraseQuery query = new PhraseQuery();
query.add(new Term("field", "seventish"));
query.add(new Term("field", "sevenon"));
PhraseQuery query = new PhraseQuery("field", "seventish", "sevenon");
checkHits(query, new int[] {});
}

View File

@ -153,9 +153,7 @@ public class TestSpanSearchEquivalence extends SearchEquivalenceTestBase {
spanQuery(new SpanTermQuery(t2))
};
SpanQuery q1 = spanQuery(new SpanNearQuery(subquery, 0, true));
PhraseQuery q2 = new PhraseQuery();
q2.add(t1);
q2.add(t2);
PhraseQuery q2 = new PhraseQuery(t1.field(), t1.bytes(), t2.bytes());
assertSameSet(q1, q2);
}

View File

@ -18,8 +18,6 @@ package org.apache.lucene.util;
*/
import java.io.IOException;
import java.io.Reader;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.MockAnalyzer;
@ -100,10 +98,10 @@ public class TestQueryBuilder extends LuceneTestCase {
}
public void testPhraseQueryPositionIncrements() throws Exception {
PhraseQuery expected = new PhraseQuery();
expected.add(new Term("field", "1"));
expected.add(new Term("field", "2"), 2);
PhraseQuery.Builder pqBuilder = new PhraseQuery.Builder();
pqBuilder.add(new Term("field", "1"), 0);
pqBuilder.add(new Term("field", "2"), 2);
PhraseQuery expected = pqBuilder.build();
CharacterRunAutomaton stopList = new CharacterRunAutomaton(new RegExp("[sS][tT][oO][pP]").toAutomaton());
Analyzer analyzer = new MockAnalyzer(random(), MockTokenizer.WHITESPACE, false, stopList);
@ -219,9 +217,7 @@ public class TestQueryBuilder extends LuceneTestCase {
// individual CJK chars as terms
SimpleCJKAnalyzer analyzer = new SimpleCJKAnalyzer();
PhraseQuery expected = new PhraseQuery();
expected.add(new Term("field", ""));
expected.add(new Term("field", ""));
PhraseQuery expected = new PhraseQuery("field", "", "");
QueryBuilder builder = new QueryBuilder(analyzer);
assertEquals(expected, builder.createPhraseQuery("field", "中国"));
@ -231,10 +227,7 @@ public class TestQueryBuilder extends LuceneTestCase {
// individual CJK chars as terms
SimpleCJKAnalyzer analyzer = new SimpleCJKAnalyzer();
PhraseQuery expected = new PhraseQuery();
expected.setSlop(3);
expected.add(new Term("field", ""));
expected.add(new Term("field", ""));
PhraseQuery expected = new PhraseQuery(3, "field", "", "");
QueryBuilder builder = new QueryBuilder(analyzer);
assertEquals(expected, builder.createPhraseQuery("field", "中国", 3));

View File

@ -232,13 +232,14 @@ public class FieldQuery {
}
}
if( overlap && src.length - i < dest.length ){
PhraseQuery pq = new PhraseQuery();
PhraseQuery.Builder pqBuilder = new PhraseQuery.Builder();
for( Term srcTerm : src )
pq.add( srcTerm );
pqBuilder.add( srcTerm );
for( int k = src.length - i; k < dest.length; k++ ){
pq.add( new Term( src[0].field(), dest[k].text() ) );
pqBuilder.add( new Term( src[0].field(), dest[k].text() ) );
}
pq.setSlop( slop );
pqBuilder.setSlop( slop );
PhraseQuery pq = pqBuilder.build();
pq.setBoost( boost );
if(!expandQueries.contains( pq ) )
expandQueries.add( pq );

View File

@ -70,10 +70,7 @@ public class HighlighterPhraseTest extends LuceneTestCase {
try {
assertEquals(1, indexReader.numDocs());
final IndexSearcher indexSearcher = newSearcher(indexReader);
final PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.add(new Term(FIELD, "fox"));
phraseQuery.add(new Term(FIELD, "jumped"));
phraseQuery.setSlop(0);
final PhraseQuery phraseQuery = new PhraseQuery(FIELD, "fox", "jumped");
TopDocs hits = indexSearcher.search(phraseQuery, 1);
assertEquals(1, hits.totalHits);
final Highlighter highlighter = new Highlighter(
@ -178,10 +175,7 @@ public class HighlighterPhraseTest extends LuceneTestCase {
try {
assertEquals(1, indexReader.numDocs());
final IndexSearcher indexSearcher = newSearcher(indexReader);
final PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.add(new Term(FIELD, "did"));
phraseQuery.add(new Term(FIELD, "jump"));
phraseQuery.setSlop(0);
final PhraseQuery phraseQuery = new PhraseQuery(FIELD, "did", "jump");
TopDocs hits = indexSearcher.search(phraseQuery, 1);
assertEquals(0, hits.totalHits);
final Highlighter highlighter = new Highlighter(
@ -218,10 +212,7 @@ public class HighlighterPhraseTest extends LuceneTestCase {
try {
assertEquals(1, indexReader.numDocs());
final IndexSearcher indexSearcher = newSearcher(indexReader);
final PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.add(new Term(FIELD, "did"));
phraseQuery.add(new Term(FIELD, "jump"));
phraseQuery.setSlop(1);
final PhraseQuery phraseQuery = new PhraseQuery(1, FIELD, "did", "jump");
TopDocs hits = indexSearcher.search(phraseQuery, 1);
assertEquals(1, hits.totalHits);
final Highlighter highlighter = new Highlighter(

View File

@ -17,8 +17,6 @@ package org.apache.lucene.search.highlight;
* limitations under the License.
*/
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@ -31,6 +29,9 @@ import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.BaseTokenStreamTestCase;
import org.apache.lucene.analysis.CachingTokenFilter;
@ -70,6 +71,7 @@ import org.apache.lucene.search.MultiPhraseQuery;
import org.apache.lucene.search.MultiTermQuery;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.PhraseQuery.Builder;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.QueryWrapperFilter;
@ -84,11 +86,11 @@ import org.apache.lucene.search.join.BitDocIdSetFilter;
import org.apache.lucene.search.join.ScoreMode;
import org.apache.lucene.search.join.ToChildBlockJoinQuery;
import org.apache.lucene.search.join.ToParentBlockJoinQuery;
import org.apache.lucene.search.payloads.SpanPayloadCheckQuery;
import org.apache.lucene.search.spans.SpanMultiTermQueryWrapper;
import org.apache.lucene.search.spans.SpanNearQuery;
import org.apache.lucene.search.spans.SpanNotQuery;
import org.apache.lucene.search.spans.SpanOrQuery;
import org.apache.lucene.search.payloads.SpanPayloadCheckQuery;
import org.apache.lucene.search.spans.SpanQuery;
import org.apache.lucene.search.spans.SpanTermQuery;
import org.apache.lucene.store.Directory;
@ -165,9 +167,7 @@ public class HighlighterTest extends BaseTokenStreamTestCase implements Formatte
}
public void testQueryScorerHits() throws Exception {
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.add(new Term(FIELD_NAME, "very"));
phraseQuery.add(new Term(FIELD_NAME, "long"));
PhraseQuery phraseQuery = new PhraseQuery(FIELD_NAME, "very", "long");
query = phraseQuery;
searcher = newSearcher(reader);
@ -289,10 +289,7 @@ public class HighlighterTest extends BaseTokenStreamTestCase implements Formatte
// highlighted
// regardless of the field name.
PhraseQuery q = new PhraseQuery();
q.setSlop(3);
q.add(new Term(FIELD_NAME, "world"));
q.add(new Term(FIELD_NAME, "flatland"));
PhraseQuery q = new PhraseQuery(3, FIELD_NAME, "world", "flatland");
String expected = "I call our <B>world</B> <B>Flatland</B>, not because we call it so,";
String observed = highlightField(q, "SOME_FIELD_NAME", s1);
@ -305,10 +302,7 @@ public class HighlighterTest extends BaseTokenStreamTestCase implements Formatte
// when the query field name differs from the name of the field being
// highlighted,
// which in this example happens to be the default field name.
q = new PhraseQuery();
q.setSlop(3);
q.add(new Term("text", "world"));
q.add(new Term("text", "flatland"));
q = new PhraseQuery(3, "text", "world", "flatland");
expected = s1;
observed = highlightField(q, FIELD_NAME, s1);
@ -362,27 +356,13 @@ public class HighlighterTest extends BaseTokenStreamTestCase implements Formatte
String f1 = "f1";
String f2 = "f2";
PhraseQuery f1ph1 = new PhraseQuery();
f1ph1.add(new Term(f1, "a"));
f1ph1.add(new Term(f1, "b"));
f1ph1.add(new Term(f1, "c"));
f1ph1.add(new Term(f1, "d"));
PhraseQuery f1ph1 = new PhraseQuery(f1, "a", "b", "c", "d");
PhraseQuery f2ph1 = new PhraseQuery();
f2ph1.add(new Term(f2, "a"));
f2ph1.add(new Term(f2, "b"));
f2ph1.add(new Term(f2, "c"));
f2ph1.add(new Term(f2, "d"));
PhraseQuery f2ph1 = new PhraseQuery(f2, "a", "b", "c", "d");
PhraseQuery f1ph2 = new PhraseQuery();
f1ph2.add(new Term(f1, "b"));
f1ph2.add(new Term(f1, "c"));
f1ph2.add(new Term(f1, "g"));
PhraseQuery f1ph2 = new PhraseQuery(f1, "b", "c", "g");
PhraseQuery f2ph2 = new PhraseQuery();
f2ph2.add(new Term(f2, "b"));
f2ph2.add(new Term(f2, "c"));
f2ph2.add(new Term(f2, "g"));
PhraseQuery f2ph2 = new PhraseQuery(f2, "b", "c", "g");
BooleanQuery booleanQuery = new BooleanQuery();
BooleanQuery leftChild = new BooleanQuery();
@ -409,10 +389,11 @@ public class HighlighterTest extends BaseTokenStreamTestCase implements Formatte
}
public void testSimpleQueryScorerPhraseHighlighting() throws Exception {
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.add(new Term(FIELD_NAME, "very"));
phraseQuery.add(new Term(FIELD_NAME, "long"));
phraseQuery.add(new Term(FIELD_NAME, "contains"), 3);
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.add(new Term(FIELD_NAME, "very"), 0);
builder.add(new Term(FIELD_NAME, "long"), 1);
builder.add(new Term(FIELD_NAME, "contains"), 3);
PhraseQuery phraseQuery = builder.build();
doSearching(phraseQuery);
int maxNumFragmentsRequired = 2;
@ -438,11 +419,12 @@ public class HighlighterTest extends BaseTokenStreamTestCase implements Formatte
numHighlights = 0;
phraseQuery = new PhraseQuery();
phraseQuery.add(new Term(FIELD_NAME, "piece"), 1);
phraseQuery.add(new Term(FIELD_NAME, "text"), 3);
phraseQuery.add(new Term(FIELD_NAME, "refers"), 4);
phraseQuery.add(new Term(FIELD_NAME, "kennedy"), 6);
builder = new PhraseQuery.Builder();
builder.add(new Term(FIELD_NAME, "piece"), 1);
builder.add(new Term(FIELD_NAME, "text"), 3);
builder.add(new Term(FIELD_NAME, "refers"), 4);
builder.add(new Term(FIELD_NAME, "kennedy"), 6);
phraseQuery = builder.build();
doSearching(phraseQuery);
@ -469,11 +451,12 @@ public class HighlighterTest extends BaseTokenStreamTestCase implements Formatte
numHighlights = 0;
phraseQuery = new PhraseQuery();
phraseQuery.add(new Term(FIELD_NAME, "lets"));
phraseQuery.add(new Term(FIELD_NAME, "lets"), 4);
phraseQuery.add(new Term(FIELD_NAME, "lets"), 8);
phraseQuery.add(new Term(FIELD_NAME, "lets"), 12);
builder = new PhraseQuery.Builder();
builder.add(new Term(FIELD_NAME, "lets"), 0);
builder.add(new Term(FIELD_NAME, "lets"), 4);
builder.add(new Term(FIELD_NAME, "lets"), 8);
builder.add(new Term(FIELD_NAME, "lets"), 12);
phraseQuery = builder.build();
doSearching(phraseQuery);
@ -661,11 +644,7 @@ public class HighlighterTest extends BaseTokenStreamTestCase implements Formatte
}
public void testSimpleQueryScorerPhraseHighlighting2() throws Exception {
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.setSlop(5);
phraseQuery.add(new Term(FIELD_NAME, "text"));
phraseQuery.add(new Term(FIELD_NAME, "piece"));
phraseQuery.add(new Term(FIELD_NAME, "long"));
PhraseQuery phraseQuery = new PhraseQuery(5, FIELD_NAME, "text", "piece", "long");
doSearching(phraseQuery);
int maxNumFragmentsRequired = 2;
@ -690,10 +669,7 @@ public class HighlighterTest extends BaseTokenStreamTestCase implements Formatte
}
public void testSimpleQueryScorerPhraseHighlighting3() throws Exception {
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.add(new Term(FIELD_NAME, "x"));
phraseQuery.add(new Term(FIELD_NAME, "y"));
phraseQuery.add(new Term(FIELD_NAME, "z"));
PhraseQuery phraseQuery = new PhraseQuery(FIELD_NAME, "x", "y", "z");
doSearching(phraseQuery);
int maxNumFragmentsRequired = 2;
@ -718,11 +694,12 @@ public class HighlighterTest extends BaseTokenStreamTestCase implements Formatte
}
public void testSimpleSpanFragmenter() throws Exception {
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.add(new Term(FIELD_NAME, "piece"));
phraseQuery.add(new Term(FIELD_NAME, "text"), 2);
phraseQuery.add(new Term(FIELD_NAME, "very"), 5);
phraseQuery.add(new Term(FIELD_NAME, "long"), 6);
Builder builder = new PhraseQuery.Builder();
builder.add(new Term(FIELD_NAME, "piece"), 0);
builder.add(new Term(FIELD_NAME, "text"), 2);
builder.add(new Term(FIELD_NAME, "very"), 5);
builder.add(new Term(FIELD_NAME, "long"), 6);
PhraseQuery phraseQuery = builder.build();
doSearching(phraseQuery);
int maxNumFragmentsRequired = 2;
@ -744,9 +721,7 @@ public class HighlighterTest extends BaseTokenStreamTestCase implements Formatte
}
phraseQuery = new PhraseQuery();
phraseQuery.add(new Term(FIELD_NAME, "been"));
phraseQuery.add(new Term(FIELD_NAME, "shot"));
phraseQuery = new PhraseQuery(FIELD_NAME, "been", "shot");
doSearching(query);
@ -773,10 +748,7 @@ public class HighlighterTest extends BaseTokenStreamTestCase implements Formatte
BooleanQuery booleanQuery = new BooleanQuery();
booleanQuery.add(new TermQuery(new Term(FIELD_NAME, "y")), Occur.SHOULD);
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.add(new Term(FIELD_NAME, "x"));
phraseQuery.add(new Term(FIELD_NAME, "y"));
phraseQuery.add(new Term(FIELD_NAME, "z"));
PhraseQuery phraseQuery = new PhraseQuery(FIELD_NAME, "x", "y", "z");
booleanQuery.add(phraseQuery, Occur.SHOULD);
doSearching(booleanQuery);
@ -1134,9 +1106,7 @@ public class HighlighterTest extends BaseTokenStreamTestCase implements Formatte
@Override
public void run() throws Exception {
numHighlights = 0;
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.add(new Term(FIELD_NAME, "john"));
phraseQuery.add(new Term(FIELD_NAME, "kennedy"));
PhraseQuery phraseQuery = new PhraseQuery(FIELD_NAME, "john", "kennedy");
doSearching(phraseQuery);
doStandardHighlights(analyzer, searcher, hits, query, HighlighterTest.this);
// Currently highlights "John" and "Kennedy" separately
@ -1217,9 +1187,7 @@ public class HighlighterTest extends BaseTokenStreamTestCase implements Formatte
@Override
public void run() throws Exception {
numHighlights = 0;
PhraseQuery pq = new PhraseQuery();
pq.add(new Term("contents", "john"));
pq.add(new Term("contents", "kennedy"));
PhraseQuery pq = new PhraseQuery("contents", "john", "kennedy");
BooleanQuery bq = new BooleanQuery();
bq.add(pq, Occur.MUST);
bq.add(TermRangeQuery.newStringRange("contents", "john", "john", true, true), Occur.FILTER);

View File

@ -58,9 +58,7 @@ public class MissesTest extends LuceneTestCase {
public void testPhraseQuery() throws IOException, InvalidTokenOffsetsException {
try (Analyzer analyzer = new MockAnalyzer(random(), MockTokenizer.WHITESPACE, false)) {
final PhraseQuery query = new PhraseQuery();
query.add(new Term("test", "foo"));
query.add(new Term("test", "bar"));
final PhraseQuery query = new PhraseQuery("test", "foo", "bar");
final Highlighter highlighter = new Highlighter(new SimpleHTMLFormatter(), new QueryScorer(query));
assertEquals("this is a <B>foo</B> <B>bar</B> example",
highlighter.getBestFragment(analyzer, "test", "this is a foo bar example"));

View File

@ -447,9 +447,7 @@ public class TestPostingsHighlighter extends LuceneTestCase {
IndexReader ir = iw.getReader();
iw.close();
IndexSearcher searcher = newSearcher(ir);
PhraseQuery query = new PhraseQuery();
query.add(new Term("body", "buddhist"));
query.add(new Term("body", "origins"));
PhraseQuery query = new PhraseQuery("body", "buddhist", "origins");
TopDocs topDocs = searcher.search(query, 10);
assertEquals(1, topDocs.totalHits);
PostingsHighlighter highlighter = new PostingsHighlighter();
@ -477,9 +475,7 @@ public class TestPostingsHighlighter extends LuceneTestCase {
IndexReader ir = iw.getReader();
iw.close();
IndexSearcher searcher = newSearcher(ir);
PhraseQuery query = new PhraseQuery();
query.add(new Term("body", "curious"));
query.add(new Term("body", "george"));
PhraseQuery query = new PhraseQuery("body", "curious", "george");
TopDocs topDocs = searcher.search(query, 10);
assertEquals(1, topDocs.totalHits);
PostingsHighlighter highlighter = new PostingsHighlighter();

View File

@ -138,12 +138,8 @@ public abstract class AbstractTestCase extends LuceneTestCase {
}
protected Query pq( float boost, int slop, String field, String... texts ){
PhraseQuery query = new PhraseQuery();
for( String text : texts ){
query.add( new Term( field, text ) );
}
PhraseQuery query = new PhraseQuery(slop, field, texts);
query.setBoost( boost );
query.setSlop( slop );
return query;
}
@ -188,11 +184,7 @@ public abstract class AbstractTestCase extends LuceneTestCase {
}
protected PhraseQuery toPhraseQuery(List<BytesRef> bytesRefs, String field) {
PhraseQuery phraseQuery = new PhraseQuery();
for (BytesRef bytesRef : bytesRefs) {
phraseQuery.add(new Term(field, bytesRef));
}
return phraseQuery;
return new PhraseQuery(field, bytesRefs.toArray(new BytesRef[0]));
}
static final class BigramAnalyzer extends Analyzer {

View File

@ -148,9 +148,7 @@ public class FastVectorHighlighterTest extends LuceneTestCase {
}
{
PhraseQuery query = new PhraseQuery();
query.add(new Term(field, "internet"));
query.add(new Term(field, "explorer"));
PhraseQuery query = new PhraseQuery(field, "internet", "explorer");
FieldQuery fieldQuery = highlighter.getFieldQuery(query, reader);
String[] bestFragments = highlighter.getBestFragments(fieldQuery, reader,
docId, field, 128, 1);
@ -197,11 +195,7 @@ public class FastVectorHighlighterTest extends LuceneTestCase {
}
{
BooleanQuery query = new BooleanQuery();
PhraseQuery pq = new PhraseQuery();
pq.add(new Term(field, "test"));
pq.add(new Term(field, "foo"));
pq.add(new Term(field, "highlighed"));
pq.setSlop(5);
PhraseQuery pq = new PhraseQuery(5, field, "test", "foo", "highlighed");
query.add(new TermQuery(new Term(field, "foo")), Occur.MUST);
query.add(pq, Occur.MUST);
query.add(new TermQuery(new Term(field, "highlighed")), Occur.MUST);
@ -218,11 +212,7 @@ public class FastVectorHighlighterTest extends LuceneTestCase {
}
{
PhraseQuery query = new PhraseQuery();
query.add(new Term(field, "test"));
query.add(new Term(field, "foo"));
query.add(new Term(field, "highlighed"));
query.setSlop(3);
PhraseQuery query = new PhraseQuery(3, field, "test", "foo", "highlighed");
FieldQuery fieldQuery = highlighter.getFieldQuery(query, reader);
String[] bestFragments = highlighter.getBestFragments(fieldQuery, reader,
docId, field, 18, 1);
@ -236,11 +226,7 @@ public class FastVectorHighlighterTest extends LuceneTestCase {
}
{
PhraseQuery query = new PhraseQuery();
query.add(new Term(field, "test"));
query.add(new Term(field, "foo"));
query.add(new Term(field, "highlighted"));
query.setSlop(30);
PhraseQuery query = new PhraseQuery(30, field, "test", "foo", "highlighed");
FieldQuery fieldQuery = highlighter.getFieldQuery(query, reader);
String[] bestFragments = highlighter.getBestFragments(fieldQuery, reader,
docId, field, 18, 1);
@ -248,11 +234,7 @@ public class FastVectorHighlighterTest extends LuceneTestCase {
}
{
BooleanQuery query = new BooleanQuery();
PhraseQuery pq = new PhraseQuery();
pq.add(new Term(field, "test"));
pq.add(new Term(field, "foo"));
pq.add(new Term(field, "highlighed"));
pq.setSlop(5);
PhraseQuery pq = new PhraseQuery(5, field, "test", "foo", "highlighed");
BooleanQuery inner = new BooleanQuery();
inner.add(pq, Occur.MUST);
inner.add(new TermQuery(new Term(field, "foo")), Occur.MUST);
@ -567,23 +549,13 @@ public class FastVectorHighlighterTest extends LuceneTestCase {
int docId = 0;
// query1: match
PhraseQuery pq = new PhraseQuery();
pq.add(new Term("field", "test"));
pq.add(new Term("field", "http"));
pq.add(new Term("field", "www"));
pq.add(new Term("field", "facebook"));
pq.add(new Term("field", "com"));
PhraseQuery pq = new PhraseQuery("field", "test", "http", "www", "facebook", "com");
FieldQuery fieldQuery = highlighter.getFieldQuery(pq, reader);
String[] bestFragments = highlighter.getBestFragments(fieldQuery, reader, docId, "field", 54, 1);
assertEquals("<b>Test: http://www.facebook.com</b>", bestFragments[0]);
// query2: match
PhraseQuery pq2 = new PhraseQuery();
pq2.add(new Term("field", "test"));
pq2.add(new Term("field", "httpwwwfacebookcom"));
pq2.add(new Term("field", "www"));
pq2.add(new Term("field", "facebook"));
pq2.add(new Term("field", "com"));
PhraseQuery pq2 = new PhraseQuery("field", "test", "httpwwwfacebookcom", "www", "facebook", "com");
fieldQuery = highlighter.getFieldQuery(pq2, reader);
bestFragments = highlighter.getBestFragments(fieldQuery, reader, docId, "field", 54, 1);
assertEquals("<b>Test: http://www.facebook.com</b>", bestFragments[0]);
@ -692,11 +664,7 @@ public class FastVectorHighlighterTest extends LuceneTestCase {
if ( terms.length == 1 ) {
q = new TermQuery( new Term( field, terms[ 0 ] ) );
} else {
PhraseQuery pq = new PhraseQuery();
for ( String term: terms ) {
pq.add( new Term( field, term ) );
}
q = pq;
q = new PhraseQuery(field, terms);
}
q.setBoost( boost );
return q;

View File

@ -48,9 +48,7 @@ public class SimpleFragListBuilderTest extends AbstractTestCase {
public void testSmallerFragSizeThanPhraseQuery() throws Exception {
SimpleFragListBuilder sflb = new SimpleFragListBuilder();
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.add(new Term(F, "abcdefgh"));
phraseQuery.add(new Term(F, "jklmnopqrs"));
PhraseQuery phraseQuery = new PhraseQuery(F, "abcdefgh", "jklmnopqrs");
FieldFragList ffl = sflb.createFieldFragList( fpl(phraseQuery, "abcdefgh jklmnopqrs" ), sflb.minFragCharSize );
assertEquals( 1, ffl.getFragInfos().size() );
@ -120,9 +118,7 @@ public class SimpleFragListBuilderTest extends AbstractTestCase {
public void testPhraseQuery() throws Exception {
SimpleFragListBuilder sflb = new SimpleFragListBuilder();
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.add(new Term(F, "a"));
phraseQuery.add(new Term(F, "b"));
PhraseQuery phraseQuery = new PhraseQuery(F, "a", "b");
FieldFragList ffl = sflb.createFieldFragList( fpl(phraseQuery, "c d e" ), 20 );
assertEquals( 0, ffl.getFragInfos().size() );
@ -138,10 +134,7 @@ public class SimpleFragListBuilderTest extends AbstractTestCase {
public void testPhraseQuerySlop() throws Exception {
SimpleFragListBuilder sflb = new SimpleFragListBuilder();
PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.setSlop(1);
phraseQuery.add(new Term(F, "a"));
phraseQuery.add(new Term(F, "b"));
PhraseQuery phraseQuery = new PhraseQuery(1, F, "a", "b");
FieldFragList ffl = sflb.createFieldFragList( fpl(phraseQuery, "a c b" ), 20 );
assertEquals( 1, ffl.getFragInfos().size() );

View File

@ -410,16 +410,14 @@ public class TestMemoryIndexAgainstRAMDir extends BaseTokenStreamTestCase {
LeafReader reader = (LeafReader) mindex.createSearcher().getIndexReader();
TestUtil.checkReader(reader);
assertEquals(7, reader.terms("field").getSumTotalTermFreq());
PhraseQuery query = new PhraseQuery();
query.add(new Term("field", "fox"));
query.add(new Term("field", "jumps"));
PhraseQuery query = new PhraseQuery("field", "fox", "jumps");
assertTrue(mindex.search(query) > 0.1);
mindex.reset();
mockAnalyzer.setPositionIncrementGap(1 + random().nextInt(10));
mindex.addField("field", "the quick brown fox", mockAnalyzer);
mindex.addField("field", "jumps over the", mockAnalyzer);
assertEquals(0, mindex.search(query), 0.00001f);
query.setSlop(10);
query = new PhraseQuery(10, "field", "fox", "jumps");
assertTrue("posGap" + mockAnalyzer.getPositionIncrementGap("field") , mindex.search(query) > 0.0001);
TestUtil.checkReader(mindex.createSearcher().getIndexReader());
}

View File

@ -109,7 +109,7 @@ public class MultiFieldQueryParser extends QueryParser
q.setBoost(boost.floatValue());
}
}
applySlop(q,slop);
q = applySlop(q,slop);
clauses.add(new BooleanClause(q, BooleanClause.Occur.SHOULD));
}
}
@ -118,16 +118,26 @@ public class MultiFieldQueryParser extends QueryParser
return getBooleanQuery(clauses, true);
}
Query q = super.getFieldQuery(field, queryText, true);
applySlop(q,slop);
q = applySlop(q,slop);
return q;
}
private void applySlop(Query q, int slop) {
private Query applySlop(Query q, int slop) {
if (q instanceof PhraseQuery) {
((PhraseQuery) q).setSlop(slop);
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.setSlop(slop);
PhraseQuery pq = (PhraseQuery) q;
org.apache.lucene.index.Term[] terms = pq.getTerms();
int[] positions = pq.getPositions();
for (int i = 0; i < terms.length; ++i) {
builder.add(terms[i], positions[i]);
}
q = builder.build();
q.setBoost(pq.getBoost());
} else if (q instanceof MultiPhraseQuery) {
((MultiPhraseQuery) q).setSlop(slop);
}
return q;
}

View File

@ -493,7 +493,16 @@ public abstract class QueryParserBase extends QueryBuilder implements CommonQuer
Query query = getFieldQuery(field, queryText, true);
if (query instanceof PhraseQuery) {
((PhraseQuery) query).setSlop(slop);
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.setSlop(slop);
PhraseQuery pq = (PhraseQuery) query;
org.apache.lucene.index.Term[] terms = pq.getTerms();
int[] positions = pq.getPositions();
for (int i = 0; i < terms.length; ++i) {
builder.add(terms[i], positions[i]);
}
query = builder.build();
query.setBoost(pq.getBoost());
}
if (query instanceof MultiPhraseQuery) {
((MultiPhraseQuery) query).setSlop(slop);

View File

@ -25,6 +25,7 @@ import org.apache.lucene.queryparser.flexible.core.nodes.FieldQueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.TokenizedPhraseQueryNode;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
/**
@ -38,10 +39,10 @@ public class PhraseQueryNodeBuilder implements StandardQueryBuilder {
}
@Override
public PhraseQuery build(QueryNode queryNode) throws QueryNodeException {
public Query build(QueryNode queryNode) throws QueryNodeException {
TokenizedPhraseQueryNode phraseNode = (TokenizedPhraseQueryNode) queryNode;
PhraseQuery phraseQuery = new PhraseQuery();
PhraseQuery.Builder builder = new PhraseQuery.Builder();
List<QueryNode> children = phraseNode.getChildren();
@ -52,13 +53,12 @@ public class PhraseQueryNodeBuilder implements StandardQueryBuilder {
.getTag(QueryTreeBuilder.QUERY_TREE_BUILDER_TAGID);
FieldQueryNode termNode = (FieldQueryNode) child;
phraseQuery.add(termQuery.getTerm(), termNode.getPositionIncrement());
builder.add(termQuery.getTerm(), termNode.getPositionIncrement());
}
}
return phraseQuery;
return builder.build();
}

View File

@ -45,7 +45,16 @@ public class SlopQueryNodeBuilder implements StandardQueryBuilder {
QueryTreeBuilder.QUERY_TREE_BUILDER_TAGID);
if (query instanceof PhraseQuery) {
((PhraseQuery) query).setSlop(phraseSlopNode.getValue());
PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.setSlop(phraseSlopNode.getValue());
PhraseQuery pq = (PhraseQuery) query;
org.apache.lucene.index.Term[] terms = pq.getTerms();
int[] positions = pq.getPositions();
for (int i = 0; i < terms.length; ++i) {
builder.add(terms[i], positions[i]);
}
query = builder.build();
query.setBoost(pq.getBoost());
} else {
((MultiPhraseQuery) query).setSlop(phraseSlopNode.getValue());

View File

@ -28,7 +28,13 @@ import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import org.apache.lucene.analysis.*;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.analysis.MockTokenFilter;
import org.apache.lucene.analysis.MockTokenizer;
import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
@ -48,8 +54,8 @@ import org.apache.lucene.queryparser.flexible.core.processors.QueryNodeProcessor
import org.apache.lucene.queryparser.flexible.messages.MessageImpl;
import org.apache.lucene.queryparser.flexible.standard.config.StandardQueryConfigHandler;
import org.apache.lucene.queryparser.flexible.standard.nodes.WildcardQueryNode;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.IndexSearcher;
@ -401,9 +407,7 @@ public class TestQPHelper extends LuceneTestCase {
// individual CJK chars as terms
SimpleCJKAnalyzer analyzer = new SimpleCJKAnalyzer();
PhraseQuery expected = new PhraseQuery();
expected.add(new Term("field", ""));
expected.add(new Term("field", ""));
PhraseQuery expected = new PhraseQuery("field", "", "");
assertEquals(expected, getQuery("\"中国\"", analyzer));
}
@ -412,10 +416,8 @@ public class TestQPHelper extends LuceneTestCase {
// individual CJK chars as terms
SimpleCJKAnalyzer analyzer = new SimpleCJKAnalyzer();
PhraseQuery expected = new PhraseQuery();
PhraseQuery expected = new PhraseQuery("field", "", "");
expected.setBoost(0.5f);
expected.add(new Term("field", ""));
expected.add(new Term("field", ""));
assertEquals(expected, getQuery("\"中国\"^0.5", analyzer));
}
@ -424,10 +426,7 @@ public class TestQPHelper extends LuceneTestCase {
// individual CJK chars as terms
SimpleCJKAnalyzer analyzer = new SimpleCJKAnalyzer();
PhraseQuery expected = new PhraseQuery();
expected.setSlop(3);
expected.add(new Term("field", ""));
expected.add(new Term("field", ""));
PhraseQuery expected = new PhraseQuery(3, "field", "", "");
assertEquals(expected, getQuery("\"中国\"~3", analyzer));
}

View File

@ -103,42 +103,29 @@ public class TestSimpleQueryParser extends LuceneTestCase {
/** test a simple phrase */
public void testPhrase() throws Exception {
PhraseQuery expected = new PhraseQuery();
expected.add(new Term("field", "foo"));
expected.add(new Term("field", "bar"));
PhraseQuery expected = new PhraseQuery("field", "foo", "bar");
assertEquals(expected, parse("\"foo bar\""));
}
/** test a simple phrase with various slop settings */
public void testPhraseWithSlop() throws Exception {
PhraseQuery expectedWithSlop = new PhraseQuery();
expectedWithSlop.add(new Term("field", "foo"));
expectedWithSlop.add(new Term("field", "bar"));
expectedWithSlop.setSlop(2);
PhraseQuery expectedWithSlop = new PhraseQuery(2, "field", "foo", "bar");
assertEquals(expectedWithSlop, parse("\"foo bar\"~2"));
PhraseQuery expectedWithMultiDigitSlop = new PhraseQuery();
expectedWithMultiDigitSlop.add(new Term("field", "foo"));
expectedWithMultiDigitSlop.add(new Term("field", "bar"));
expectedWithMultiDigitSlop.setSlop(10);
PhraseQuery expectedWithMultiDigitSlop = new PhraseQuery(10, "field", "foo", "bar");
assertEquals(expectedWithMultiDigitSlop, parse("\"foo bar\"~10"));
PhraseQuery expectedNoSlop = new PhraseQuery();
expectedNoSlop.add(new Term("field", "foo"));
expectedNoSlop.add(new Term("field", "bar"));
PhraseQuery expectedNoSlop = new PhraseQuery("field", "foo", "bar");
assertEquals("Ignore trailing tilde with no slop", expectedNoSlop, parse("\"foo bar\"~"));
assertEquals("Ignore non-numeric trailing slop", expectedNoSlop, parse("\"foo bar\"~a"));
assertEquals("Ignore non-numeric trailing slop", expectedNoSlop, parse("\"foo bar\"~1a"));
assertEquals("Ignore negative trailing slop", expectedNoSlop, parse("\"foo bar\"~-1"));
PhraseQuery pq = new PhraseQuery();
pq.add(new Term("field", "foo"));
pq.add(new Term("field", "bar"));
pq.setSlop(12);
PhraseQuery pq = new PhraseQuery(12, "field", "foo", "bar");
BooleanQuery expectedBoolean = new BooleanQuery();
expectedBoolean.add(pq, Occur.MUST);
@ -165,12 +152,8 @@ public class TestSimpleQueryParser extends LuceneTestCase {
/** test some AND'd phrases using '+' operator */
public void testANDPhrase() throws Exception {
PhraseQuery phrase1 = new PhraseQuery();
phrase1.add(new Term("field", "foo"));
phrase1.add(new Term("field", "bar"));
PhraseQuery phrase2 = new PhraseQuery();
phrase2.add(new Term("field", "star"));
phrase2.add(new Term("field", "wars"));
PhraseQuery phrase1 = new PhraseQuery("field", "foo", "bar");
PhraseQuery phrase2 = new PhraseQuery("field", "star", "wars");
BooleanQuery expected = new BooleanQuery();
expected.add(phrase1, Occur.MUST);
expected.add(phrase2, Occur.MUST);
@ -209,12 +192,8 @@ public class TestSimpleQueryParser extends LuceneTestCase {
/** test some OR'd phrases using '|' operator */
public void testORPhrase() throws Exception {
PhraseQuery phrase1 = new PhraseQuery();
phrase1.add(new Term("field", "foo"));
phrase1.add(new Term("field", "bar"));
PhraseQuery phrase2 = new PhraseQuery();
phrase2.add(new Term("field", "star"));
phrase2.add(new Term("field", "wars"));
PhraseQuery phrase1 = new PhraseQuery("field", "foo", "bar");
PhraseQuery phrase2 = new PhraseQuery("field", "star", "wars");
BooleanQuery expected = new BooleanQuery();
expected.add(phrase1, Occur.SHOULD);
expected.add(phrase2, Occur.SHOULD);
@ -324,9 +303,7 @@ public class TestSimpleQueryParser extends LuceneTestCase {
}
public void testGarbagePhrase() throws Exception {
PhraseQuery expected = new PhraseQuery();
expected.add(new Term("field", "star"));
expected.add(new Term("field", "wars"));
PhraseQuery expected = new PhraseQuery("field", "star", "wars");
assertEquals(expected, parse("\"star wars\""));
assertEquals(expected, parse("\"star wars\\ \""));
@ -614,9 +591,7 @@ public class TestSimpleQueryParser extends LuceneTestCase {
}
public void testDisableSlop() {
PhraseQuery expectedPhrase = new PhraseQuery();
expectedPhrase.add(new Term("field", "foo"));
expectedPhrase.add(new Term("field", "bar"));
PhraseQuery expectedPhrase = new PhraseQuery("field", "foo", "bar");
BooleanQuery expected = new BooleanQuery();
expected.add(expectedPhrase, Occur.MUST);

View File

@ -298,9 +298,7 @@ public abstract class QueryParserTestBase extends LuceneTestCase {
// individual CJK chars as terms
SimpleCJKAnalyzer analyzer = new SimpleCJKAnalyzer();
PhraseQuery expected = new PhraseQuery();
expected.add(new Term("field", ""));
expected.add(new Term("field", ""));
PhraseQuery expected = new PhraseQuery("field", "", "");
assertEquals(expected, getQuery("\"中国\"", analyzer));
}
@ -309,10 +307,8 @@ public abstract class QueryParserTestBase extends LuceneTestCase {
// individual CJK chars as terms
SimpleCJKAnalyzer analyzer = new SimpleCJKAnalyzer();
PhraseQuery expected = new PhraseQuery();
PhraseQuery expected = new PhraseQuery("field", "", "");
expected.setBoost(0.5f);
expected.add(new Term("field", ""));
expected.add(new Term("field", ""));
assertEquals(expected, getQuery("\"中国\"^0.5", analyzer));
}
@ -321,10 +317,7 @@ public abstract class QueryParserTestBase extends LuceneTestCase {
// individual CJK chars as terms
SimpleCJKAnalyzer analyzer = new SimpleCJKAnalyzer();
PhraseQuery expected = new PhraseQuery();
expected.setSlop(3);
expected.add(new Term("field", ""));
expected.add(new Term("field", ""));
PhraseQuery expected = new PhraseQuery(3, "field", "", "");
assertEquals(expected, getQuery("\"中国\"~3", analyzer));
}
@ -333,9 +326,7 @@ public abstract class QueryParserTestBase extends LuceneTestCase {
// individual CJK chars as terms
SimpleCJKAnalyzer analyzer = new SimpleCJKAnalyzer();
PhraseQuery expected = new PhraseQuery();
expected.add(new Term("field", ""));
expected.add(new Term("field", ""));
PhraseQuery expected = new PhraseQuery("field", "", "");
CommonQueryParserConfiguration qp = getParserConfig(analyzer);
setAutoGeneratePhraseQueries(qp, true);
assertEquals(expected, getQuery("中国",qp));
@ -1259,10 +1250,10 @@ public abstract class QueryParserTestBase extends LuceneTestCase {
new MockAnalyzer(random(), MockTokenizer.WHITESPACE, false, stopStopList));
qp.setEnablePositionIncrements(true);
PhraseQuery phraseQuery = new PhraseQuery();
PhraseQuery.Builder phraseQuery = new PhraseQuery.Builder();
phraseQuery.add(new Term("field", "1"));
phraseQuery.add(new Term("field", "2"), 2);
assertEquals(phraseQuery, getQuery("\"1 stop 2\"",qp));
assertEquals(phraseQuery.build(), getQuery("\"1 stop 2\"",qp));
}
public void testMatchAllQueryParsing() throws Exception {

View File

@ -673,9 +673,7 @@ public abstract class ThreadedIndexingAndSearchingTestCase extends LuceneTestCas
protected void smokeTestSearcher(IndexSearcher s) throws Exception {
runQuery(s, new TermQuery(new Term("body", "united")));
runQuery(s, new TermQuery(new Term("titleTokenized", "states")));
PhraseQuery pq = new PhraseQuery();
pq.add(new Term("body", "united"));
pq.add(new Term("body", "states"));
PhraseQuery pq = new PhraseQuery("body", "united", "states");
runQuery(s, pq);
}
}

View File

@ -151,10 +151,7 @@ public abstract class SearchEquivalenceTestBase extends LuceneTestCase {
query = TermRangeQuery.newStringRange("field", "a", "" + randomChar(), true, true);
} else {
// use a query with a two-phase approximation
PhraseQuery phrase = new PhraseQuery();
phrase.add(new Term("field", "" + randomChar()));
phrase.add(new Term("field", "" + randomChar()));
phrase.setSlop(100);
PhraseQuery phrase = new PhraseQuery(100, "field", "" + randomChar(), "" + randomChar());
query = phrase;
}

View File

@ -387,7 +387,16 @@ public abstract class SolrQueryParserBase extends QueryBuilder {
if (subQParser == null) {
if (query instanceof PhraseQuery) {
((PhraseQuery) query).setSlop(slop);
PhraseQuery pq = (PhraseQuery) query;
Term[] terms = pq.getTerms();
int[] positions = pq.getPositions();
PhraseQuery.Builder builder = new PhraseQuery.Builder();
for (int i = 0; i < terms.length; ++i) {
builder.add(terms[i], positions[i]);
}
builder.setSlop(slop);
query = builder.build();
query.setBoost(pq.getBoost());
}
if (query instanceof MultiPhraseQuery) {
((MultiPhraseQuery) query).setSlop(slop);

View File

@ -17,12 +17,22 @@
package org.apache.solr.search;
import com.google.common.base.Function;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.core.StopFilterFactory;
import org.apache.lucene.analysis.util.TokenFilterFactory;
import org.apache.lucene.index.Term;
import org.apache.lucene.queries.function.BoostedQuery;
import org.apache.lucene.queries.function.FunctionQuery;
import org.apache.lucene.queries.function.ValueSource;
@ -45,17 +55,9 @@ import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.schema.FieldType;
import org.apache.solr.util.SolrPluginUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.base.Function;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
/**
* Query parser that generates DisjunctionMaxQueries based on user configuration.
@ -1240,7 +1242,14 @@ public class ExtendedDismaxQParser extends QParser {
if (query instanceof PhraseQuery) {
PhraseQuery pq = (PhraseQuery)query;
if (minClauseSize > 1 && pq.getTerms().length < minClauseSize) return null;
((PhraseQuery)query).setSlop(slop);
PhraseQuery.Builder builder = new PhraseQuery.Builder();
Term[] terms = pq.getTerms();
int[] positions = pq.getPositions();
for (int i = 0; i < terms.length; ++i) {
builder.add(terms[i], positions[i]);
}
builder.setSlop(slop);
query = builder.build();
} else if (query instanceof MultiPhraseQuery) {
MultiPhraseQuery pq = (MultiPhraseQuery)query;
if (minClauseSize > 1 && pq.getTermArrays().size() < minClauseSize) return null;