mirror of https://github.com/apache/lucene.git
Most of Wolf Siberski's patch to fix #35241/#31841: MulitSearcher failed on WildcardQuery etc.
-this has not been committed: removal of mergeBooleanQueries(); change to BooleanQuery.equals() -added: a test case that is commented out which shows strange queries like "multi* multi* foo" don't work properly git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@201453 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
00b3e9d8a4
commit
52cda0c4ef
|
@ -371,11 +371,6 @@ public class BooleanQuery extends Query {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// inherit javadoc
|
|
||||||
public Query combine(Query[] queries) {
|
|
||||||
return Query.mergeBooleanQueries(queries);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object clone() {
|
public Object clone() {
|
||||||
BooleanQuery clone = (BooleanQuery)super.clone();
|
BooleanQuery clone = (BooleanQuery)super.clone();
|
||||||
clone.clauses = (Vector)this.clauses.clone();
|
clone.clauses = (Vector)this.clauses.clone();
|
||||||
|
|
|
@ -67,11 +67,6 @@ public abstract class MultiTermQuery extends Query {
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Query combine(Query[] queries) {
|
|
||||||
return Query.mergeBooleanQueries(queries);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Prints a user-readable version of this query. */
|
/** Prints a user-readable version of this query. */
|
||||||
public String toString(String field) {
|
public String toString(String field) {
|
||||||
StringBuffer buffer = new StringBuffer();
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
|
|
@ -60,10 +60,6 @@ public class PrefixQuery extends Query {
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Query combine(Query[] queries) {
|
|
||||||
return Query.mergeBooleanQueries(queries);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Prints a user-readable version of this query. */
|
/** Prints a user-readable version of this query. */
|
||||||
public String toString(String field) {
|
public String toString(String field) {
|
||||||
StringBuffer buffer = new StringBuffer();
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
|
|
@ -104,16 +104,47 @@ public abstract class Query implements java.io.Serializable, Cloneable {
|
||||||
|
|
||||||
/** Expert: called when re-writing queries under MultiSearcher.
|
/** Expert: called when re-writing queries under MultiSearcher.
|
||||||
*
|
*
|
||||||
* <p>Only implemented by derived queries, with no
|
* Create a single query suitable for use by all subsearchers (in 1-1
|
||||||
* {@link #createWeight(Searcher)} implementation.
|
* correspondence with queries). This is an optimization of the OR of
|
||||||
|
* all queries. We handle the common optimization cases of equal
|
||||||
|
* queries and overlapping clauses of boolean OR queries (as generated
|
||||||
|
* by MultiTermQuery.rewrite() and RangeQuery.rewrite()).
|
||||||
|
* Be careful overriding this method as queries[0] determines which
|
||||||
|
* method will be called and is not necessarily of the same type as
|
||||||
|
* the other queries.
|
||||||
*/
|
*/
|
||||||
public Query combine(Query[] queries) {
|
public Query combine(Query[] queries) {
|
||||||
|
HashSet uniques = new HashSet();
|
||||||
for (int i = 0; i < queries.length; i++) {
|
for (int i = 0; i < queries.length; i++) {
|
||||||
if (!this.equals(queries[i])) {
|
Query query = queries[i];
|
||||||
throw new IllegalArgumentException();
|
BooleanClause[] clauses = null;
|
||||||
|
// check if we can split the query into clauses
|
||||||
|
boolean splittable = (query instanceof BooleanQuery);
|
||||||
|
if(splittable){
|
||||||
|
BooleanQuery bq = (BooleanQuery) query;
|
||||||
|
splittable = bq.isCoordDisabled();
|
||||||
|
clauses = bq.getClauses();
|
||||||
|
for (int j = 0; splittable && j < clauses.length; j++) {
|
||||||
|
splittable = (clauses[j].getOccur() == BooleanClause.Occur.SHOULD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this;
|
if(splittable){
|
||||||
|
for (int j = 0; j < clauses.length; j++) {
|
||||||
|
uniques.add(clauses[j].getQuery());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uniques.add(query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// optimization: if we have just one query, just return it
|
||||||
|
if(uniques.size() == 1){
|
||||||
|
return (Query)uniques.iterator().next();
|
||||||
|
}
|
||||||
|
Iterator it = uniques.iterator();
|
||||||
|
BooleanQuery result = new BooleanQuery(true);
|
||||||
|
while (it.hasNext())
|
||||||
|
result.add((Query) it.next(), BooleanClause.Occur.SHOULD);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -105,10 +105,6 @@ public class RangeQuery extends Query
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Query combine(Query[] queries) {
|
|
||||||
return Query.mergeBooleanQueries(queries);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the field name for this query */
|
/** Returns the field name for this query */
|
||||||
public String getField() {
|
public String getField() {
|
||||||
return (lowerTerm != null ? lowerTerm.field() : upperTerm.field());
|
return (lowerTerm != null ? lowerTerm.field() : upperTerm.field());
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package org.apache.lucene.search;
|
package org.apache.lucene.search;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copyright 2005 The Apache Software Foundation
|
* Copyright 2004 The Apache Software Foundation
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -24,7 +24,8 @@ import org.apache.lucene.analysis.standard.StandardAnalyzer;
|
||||||
import org.apache.lucene.document.Document;
|
import org.apache.lucene.document.Document;
|
||||||
import org.apache.lucene.document.Field;
|
import org.apache.lucene.document.Field;
|
||||||
import org.apache.lucene.index.IndexWriter;
|
import org.apache.lucene.index.IndexWriter;
|
||||||
import org.apache.lucene.index.Term;
|
import org.apache.lucene.queryParser.ParseException;
|
||||||
|
import org.apache.lucene.queryParser.QueryParser;
|
||||||
import org.apache.lucene.store.Directory;
|
import org.apache.lucene.store.Directory;
|
||||||
import org.apache.lucene.store.RAMDirectory;
|
import org.apache.lucene.store.RAMDirectory;
|
||||||
|
|
||||||
|
@ -34,70 +35,128 @@ import org.apache.lucene.store.RAMDirectory;
|
||||||
*
|
*
|
||||||
* @version $Id: TestMultiSearcher.java 150492 2004-09-06 22:01:49Z dnaber $
|
* @version $Id: TestMultiSearcher.java 150492 2004-09-06 22:01:49Z dnaber $
|
||||||
*/
|
*/
|
||||||
public class TestMultiSearcherRanking extends TestCase
|
public class TestMultiSearcherRanking extends TestCase {
|
||||||
{
|
|
||||||
|
|
||||||
private final Query query = new TermQuery(new Term("body", "three"));
|
private final boolean verbose = false; // set to true to output hits
|
||||||
|
private final String FIELD_NAME = "body";
|
||||||
|
private Searcher multiSearcher;
|
||||||
|
private Searcher singleSearcher;
|
||||||
|
|
||||||
public void testMultiSearcherRanking() throws IOException {
|
public void testOneTermQuery() throws IOException, ParseException {
|
||||||
Hits multiSearcherHits = multi();
|
checkQuery("three");
|
||||||
Hits singleSearcherHits = single();
|
}
|
||||||
|
|
||||||
|
public void testTwoTermQuery() throws IOException, ParseException {
|
||||||
|
checkQuery("three foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testPrefixQuery() throws IOException, ParseException {
|
||||||
|
checkQuery("multi*");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFuzzyQuery() throws IOException, ParseException {
|
||||||
|
checkQuery("multiThree~");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testRangeQuery() throws IOException, ParseException {
|
||||||
|
checkQuery("{multiA TO multiP}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultiPhraseQuery() throws IOException, ParseException {
|
||||||
|
checkQuery("\"blueberry pi*\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNoMatchQuery() throws IOException, ParseException {
|
||||||
|
checkQuery("+three +nomatch");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public void testTermRepeatedQuery() throws IOException, ParseException {
|
||||||
|
// TODO: this corner case yields different results.
|
||||||
|
checkQuery("multi* multi* foo");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checks if a query yields the same result when executed on
|
||||||
|
* a single IndexSearcher containing all documents and on a
|
||||||
|
* MultiSearcher aggregating sub-searchers
|
||||||
|
* @param queryStr the query to check.
|
||||||
|
* @throws IOException
|
||||||
|
* @throws ParseException
|
||||||
|
*/
|
||||||
|
private void checkQuery(String queryStr) throws IOException, ParseException {
|
||||||
|
// check result hit ranking
|
||||||
|
if(verbose) System.out.println("Query: " + queryStr);
|
||||||
|
Query query = QueryParser.parse(queryStr, FIELD_NAME,
|
||||||
|
new StandardAnalyzer());
|
||||||
|
Hits multiSearcherHits = multiSearcher.search(query);
|
||||||
|
Hits singleSearcherHits = singleSearcher.search(query);
|
||||||
assertEquals(multiSearcherHits.length(), singleSearcherHits.length());
|
assertEquals(multiSearcherHits.length(), singleSearcherHits.length());
|
||||||
for (int i = 0; i < multiSearcherHits.length(); i++) {
|
for (int i = 0; i < multiSearcherHits.length(); i++) {
|
||||||
assertEquals(multiSearcherHits.score(i), singleSearcherHits.score(i), 0.001f);
|
|
||||||
Document docMulti = multiSearcherHits.doc(i);
|
Document docMulti = multiSearcherHits.doc(i);
|
||||||
Document docSingle = singleSearcherHits.doc(i);
|
Document docSingle = singleSearcherHits.doc(i);
|
||||||
assertEquals(docMulti.get("body"), docSingle.get("body"));
|
if(verbose) System.out.println("Multi: " + docMulti.get(FIELD_NAME) + " score="
|
||||||
|
+ multiSearcherHits.score(i));
|
||||||
|
if(verbose) System.out.println("Single: " + docSingle.get(FIELD_NAME) + " score="
|
||||||
|
+ singleSearcherHits.score(i));
|
||||||
|
assertEquals(multiSearcherHits.score(i), singleSearcherHits.score(i),
|
||||||
|
0.001f);
|
||||||
|
assertEquals(docMulti.get(FIELD_NAME), docSingle.get(FIELD_NAME));
|
||||||
}
|
}
|
||||||
|
if(verbose) System.out.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collection 1+2 searched with MultiSearcher:
|
/**
|
||||||
private Hits multi() throws IOException {
|
* initializes multiSearcher and singleSearcher with the same document set
|
||||||
|
*/
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
// create MultiSearcher from two seperate searchers
|
||||||
Directory d1 = new RAMDirectory();
|
Directory d1 = new RAMDirectory();
|
||||||
IndexWriter iw = new IndexWriter(d1, new StandardAnalyzer(), true);
|
IndexWriter iw1 = new IndexWriter(d1, new StandardAnalyzer(), true);
|
||||||
addCollection1(iw);
|
addCollection1(iw1);
|
||||||
iw.close();
|
iw1.close();
|
||||||
|
|
||||||
Directory d2 = new RAMDirectory();
|
Directory d2 = new RAMDirectory();
|
||||||
iw = new IndexWriter(d2, new StandardAnalyzer(), true);
|
IndexWriter iw2 = new IndexWriter(d2, new StandardAnalyzer(), true);
|
||||||
addCollection2(iw);
|
addCollection2(iw2);
|
||||||
iw.close();
|
iw2.close();
|
||||||
|
|
||||||
Searchable[] s = new Searchable[2];
|
Searchable[] s = new Searchable[2];
|
||||||
s[0] = new IndexSearcher(d1);
|
s[0] = new IndexSearcher(d1);
|
||||||
s[1] = new IndexSearcher(d2);
|
s[1] = new IndexSearcher(d2);
|
||||||
MultiSearcher ms = new MultiSearcher(s);
|
multiSearcher = new MultiSearcher(s);
|
||||||
Hits hits = ms.search(query);
|
|
||||||
return hits;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collection 1+2 indexed together:
|
// create IndexSearcher which contains all documents
|
||||||
private Hits single() throws IOException {
|
|
||||||
Directory d = new RAMDirectory();
|
Directory d = new RAMDirectory();
|
||||||
IndexWriter iw = new IndexWriter(d, new StandardAnalyzer(), true);
|
IndexWriter iw = new IndexWriter(d, new StandardAnalyzer(), true);
|
||||||
addCollection1(iw);
|
addCollection1(iw);
|
||||||
addCollection2(iw);
|
addCollection2(iw);
|
||||||
iw.close();
|
iw.close();
|
||||||
IndexSearcher is = new IndexSearcher(d);
|
singleSearcher = new IndexSearcher(d);
|
||||||
Hits hits = is.search(query);
|
|
||||||
return hits;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addCollection1(IndexWriter iw) throws IOException {
|
private void addCollection1(IndexWriter iw) throws IOException {
|
||||||
add("one blah three", iw);
|
add("one blah three", iw);
|
||||||
add("one foo three", iw);
|
add("one foo three multiOne", iw);
|
||||||
add("one foobar three", iw);
|
add("one foobar three multiThree", iw);
|
||||||
|
add("blueberry pie", iw);
|
||||||
|
add("blueberry strudel", iw);
|
||||||
|
add("blueberry pizza", iw);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addCollection2(IndexWriter iw) throws IOException {
|
private void addCollection2(IndexWriter iw) throws IOException {
|
||||||
add("two blah three", iw);
|
add("two blah three", iw);
|
||||||
add("two foo xxx", iw);
|
add("two foo xxx multiTwo", iw);
|
||||||
add("two foobar xxx", iw);
|
add("two foobar xxx multiThreee", iw);
|
||||||
|
add("blueberry chewing gum", iw);
|
||||||
|
add("bluebird pizza", iw);
|
||||||
|
add("bluebird foobar pizza", iw);
|
||||||
|
add("piccadilly circus", iw);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void add(String value, IndexWriter iw) throws IOException {
|
private void add(String value, IndexWriter iw) throws IOException {
|
||||||
Document d = new Document();
|
Document d = new Document();
|
||||||
d.add(new Field("body", value, Field.Store.YES, Field.Index.TOKENIZED));
|
d.add(new Field(FIELD_NAME, value, Field.Store.YES, Field.Index.TOKENIZED));
|
||||||
iw.addDocument(d);
|
iw.addDocument(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue