mirror of
https://github.com/querydsl/querydsl.git
synced 2026-06-24 21:07:26 +08:00
LuceneSerializer: Occur.MUST_NOT queries are no longer wrapped in other BooleanQueries. E.g. +(-title:foobar) no longer occurs.
This commit is contained in:
parent
dfdcacf7ca
commit
38eb31ad33
@ -17,7 +17,17 @@ import java.util.Map;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.queryParser.QueryParser;
|
||||
import org.apache.lucene.search.*;
|
||||
import org.apache.lucene.search.BooleanClause;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.search.NumericRangeQuery;
|
||||
import org.apache.lucene.search.PhraseQuery;
|
||||
import org.apache.lucene.search.PrefixQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.Sort;
|
||||
import org.apache.lucene.search.SortField;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
import org.apache.lucene.search.TermRangeQuery;
|
||||
import org.apache.lucene.search.WildcardQuery;
|
||||
import org.apache.lucene.search.BooleanClause.Occur;
|
||||
import org.apache.lucene.util.NumericUtils;
|
||||
|
||||
@ -37,18 +47,18 @@ import com.mysema.query.types.PathType;
|
||||
*
|
||||
*/
|
||||
public class LuceneSerializer {
|
||||
|
||||
private static final Map<Class<?>,Integer> sortFields = new HashMap<Class<?>,Integer>();
|
||||
|
||||
static{
|
||||
sortFields.put(Integer.class, SortField.INT);
|
||||
sortFields.put(Float.class, SortField.FLOAT);
|
||||
sortFields.put(Long.class, SortField.LONG);
|
||||
sortFields.put(Double.class, SortField.DOUBLE);
|
||||
sortFields.put(Short.class, SortField.SHORT);
|
||||
sortFields.put(Byte.class, SortField.BYTE);
|
||||
sortFields.put(BigDecimal.class, SortField.DOUBLE);
|
||||
sortFields.put(BigInteger.class, SortField.LONG);
|
||||
|
||||
private static final Map<Class<?>, Integer> sortFields = new HashMap<Class<?>, Integer>();
|
||||
|
||||
static {
|
||||
sortFields.put(Integer.class, SortField.INT);
|
||||
sortFields.put(Float.class, SortField.FLOAT);
|
||||
sortFields.put(Long.class, SortField.LONG);
|
||||
sortFields.put(Double.class, SortField.DOUBLE);
|
||||
sortFields.put(Short.class, SortField.SHORT);
|
||||
sortFields.put(Byte.class, SortField.BYTE);
|
||||
sortFields.put(BigDecimal.class, SortField.DOUBLE);
|
||||
sortFields.put(BigInteger.class, SortField.LONG);
|
||||
}
|
||||
|
||||
public static final LuceneSerializer DEFAULT = new LuceneSerializer(false, true);
|
||||
@ -96,22 +106,36 @@ public class LuceneSerializer {
|
||||
return le(operation);
|
||||
} else if (op == Ops.GOE || op == Ops.AOE) {
|
||||
return ge(operation);
|
||||
} else if (op == PathType.DELEGATE){
|
||||
} else if (op == PathType.DELEGATE) {
|
||||
return toQuery(operation.getArg(0));
|
||||
}
|
||||
throw new UnsupportedOperationException("Illegal operation " + operation);
|
||||
}
|
||||
|
||||
private Query toTwoHandSidedQuery(Operation<?> operation, Occur occur) {
|
||||
// TODO Flatten similar queries(?)
|
||||
Query lhs = toQuery(operation.getArg(0));
|
||||
Query rhs = toQuery(operation.getArg(1));
|
||||
BooleanQuery bq = new BooleanQuery();
|
||||
bq.add(lhs, occur);
|
||||
bq.add(rhs, occur);
|
||||
bq.add(createBooleanClause(lhs, occur));
|
||||
bq.add(createBooleanClause(rhs, occur));
|
||||
return bq;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the query is a BooleanQuery and it contains a single Occur.MUST_NOT
|
||||
* clause it will be returned as is. Otherwise it will be wrapped in a
|
||||
* BooleanClause with the given Occur.
|
||||
*/
|
||||
private BooleanClause createBooleanClause(Query query, Occur occur) {
|
||||
if (query instanceof BooleanQuery) {
|
||||
BooleanClause[] clauses = ((BooleanQuery) query).getClauses();
|
||||
if (clauses.length == 1 && clauses[0].getOccur().equals(Occur.MUST_NOT)) {
|
||||
return clauses[0];
|
||||
}
|
||||
}
|
||||
return new BooleanClause(query, occur);
|
||||
}
|
||||
|
||||
private Query like(Operation<?> operation) {
|
||||
verifyArguments(operation);
|
||||
String field = toField(operation.getArg(0));
|
||||
@ -125,38 +149,39 @@ public class LuceneSerializer {
|
||||
}
|
||||
return new WildcardQuery(new Term(field, normalize(terms[0])));
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Query eq(Operation<?> operation) {
|
||||
verifyArguments(operation);
|
||||
String field = toField(operation.getArg(0));
|
||||
if (Number.class.isAssignableFrom(operation.getArg(1).getType())){
|
||||
return new TermQuery(new Term(field, convertNumber(((Constant<Number>)operation.getArg(1)).getConstant())));
|
||||
}else{
|
||||
return eq(field, createTerms(operation.getArg(1)));
|
||||
if (Number.class.isAssignableFrom(operation.getArg(1).getType())) {
|
||||
return new TermQuery(new Term(field, convertNumber(((Constant<Number>) operation
|
||||
.getArg(1)).getConstant())));
|
||||
}
|
||||
return eq(field, createTerms(operation.getArg(1)));
|
||||
}
|
||||
|
||||
private String convertNumber(Number number){
|
||||
if (Integer.class.isInstance(number)){
|
||||
return NumericUtils.intToPrefixCoded(number.intValue());
|
||||
}else if (Double.class.isInstance(number)){
|
||||
return NumericUtils.doubleToPrefixCoded(number.doubleValue());
|
||||
}else if (Long.class.isInstance(number)){
|
||||
return NumericUtils.longToPrefixCoded(number.longValue());
|
||||
}else if (Float.class.isInstance(number)){
|
||||
return NumericUtils.floatToPrefixCoded(number.floatValue());
|
||||
}else if (Byte.class.isInstance(number)){
|
||||
return NumericUtils.intToPrefixCoded(number.intValue());
|
||||
}else if (Short.class.isInstance(number)){
|
||||
return NumericUtils.intToPrefixCoded(number.intValue());
|
||||
}else if (BigDecimal.class.isInstance(number)){
|
||||
return NumericUtils.doubleToPrefixCoded(number.doubleValue());
|
||||
}else if (BigInteger.class.isInstance(number)){
|
||||
return NumericUtils.longToPrefixCoded(number.longValue());
|
||||
}else{
|
||||
throw new IllegalArgumentException("Unsupported numeric type " + number.getClass().getName());
|
||||
}
|
||||
|
||||
private String convertNumber(Number number) {
|
||||
if (Integer.class.isInstance(number)) {
|
||||
return NumericUtils.intToPrefixCoded(number.intValue());
|
||||
} else if (Double.class.isInstance(number)) {
|
||||
return NumericUtils.doubleToPrefixCoded(number.doubleValue());
|
||||
} else if (Long.class.isInstance(number)) {
|
||||
return NumericUtils.longToPrefixCoded(number.longValue());
|
||||
} else if (Float.class.isInstance(number)) {
|
||||
return NumericUtils.floatToPrefixCoded(number.floatValue());
|
||||
} else if (Byte.class.isInstance(number)) {
|
||||
return NumericUtils.intToPrefixCoded(number.intValue());
|
||||
} else if (Short.class.isInstance(number)) {
|
||||
return NumericUtils.intToPrefixCoded(number.intValue());
|
||||
} else if (BigDecimal.class.isInstance(number)) {
|
||||
return NumericUtils.doubleToPrefixCoded(number.doubleValue());
|
||||
} else if (BigInteger.class.isInstance(number)) {
|
||||
return NumericUtils.longToPrefixCoded(number.longValue());
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported numeric type "
|
||||
+ number.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
private Query eq(String field, String[] terms) {
|
||||
@ -234,7 +259,8 @@ public class LuceneSerializer {
|
||||
private Query between(Operation<?> operation) {
|
||||
verifyArguments(operation);
|
||||
// TODO Phrase not properly supported
|
||||
return range(toField(operation.getArg(0)), operation.getArg(1), operation.getArg(2), true, true);
|
||||
return range(toField(operation.getArg(0)), operation.getArg(1), operation.getArg(2), true,
|
||||
true);
|
||||
}
|
||||
|
||||
private Query lt(Operation<?> operation) {
|
||||
@ -259,33 +285,34 @@ public class LuceneSerializer {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Query range(String field, Expr<?> min, Expr<?> max, boolean minInc, boolean maxInc) {
|
||||
if (min != null && Number.class.isAssignableFrom(min.getType()) || max != null && Number.class.isAssignableFrom(max.getType())) {
|
||||
Class<? extends Number> numType = (Class)(min != null ? min.getType() : max.getType());
|
||||
return numericRange((Class)numType, field,
|
||||
(Number)(min == null ? null : ((Constant) min).getConstant()),
|
||||
(Number)(max == null ? null : ((Constant) max).getConstant()),
|
||||
minInc, maxInc);
|
||||
} else {
|
||||
return stringRange(field, min, max, minInc, maxInc);
|
||||
if (min != null && Number.class.isAssignableFrom(min.getType()) || max != null
|
||||
&& Number.class.isAssignableFrom(max.getType())) {
|
||||
Class<? extends Number> numType = (Class) (min != null ? min.getType() : max.getType());
|
||||
return numericRange((Class) numType, field, (Number) (min == null ? null
|
||||
: ((Constant) min).getConstant()), (Number) (max == null ? null
|
||||
: ((Constant) max).getConstant()), minInc, maxInc);
|
||||
}
|
||||
return stringRange(field, min, max, minInc, maxInc);
|
||||
}
|
||||
|
||||
private <N extends Number> NumericRangeQuery<?> numericRange(Class<N> clazz, String field, N min, N max, boolean minInc, boolean maxInc){
|
||||
if (clazz.equals(Integer.class)){
|
||||
return NumericRangeQuery.newIntRange(field, (Integer)min, (Integer)max, minInc, maxInc);
|
||||
}else if (clazz.equals(Double.class)){
|
||||
return NumericRangeQuery.newDoubleRange(field, (Double)min, (Double)max, minInc, minInc);
|
||||
}else if (clazz.equals(Float.class)){
|
||||
return NumericRangeQuery.newFloatRange(field, (Float)min, (Float)max, minInc, minInc);
|
||||
}else if (clazz.equals(Long.class)){
|
||||
return NumericRangeQuery.newLongRange(field, (Long)min, (Long)max, minInc, minInc);
|
||||
}else if (clazz.equals(Byte.class) || clazz.equals(Short.class)){
|
||||
return NumericRangeQuery.newIntRange(field,
|
||||
min != null ? min.intValue() : null,
|
||||
max != null ? max.intValue() : null, minInc, maxInc);
|
||||
}else{
|
||||
throw new IllegalArgumentException("Unsupported numeric type " + clazz.getName());
|
||||
}
|
||||
|
||||
private <N extends Number> NumericRangeQuery<?> numericRange(Class<N> clazz, String field,
|
||||
N min, N max, boolean minInc, boolean maxInc) {
|
||||
if (clazz.equals(Integer.class)) {
|
||||
return NumericRangeQuery.newIntRange(field, (Integer) min, (Integer) max, minInc,
|
||||
maxInc);
|
||||
} else if (clazz.equals(Double.class)) {
|
||||
return NumericRangeQuery.newDoubleRange(field, (Double) min, (Double) max, minInc,
|
||||
minInc);
|
||||
} else if (clazz.equals(Float.class)) {
|
||||
return NumericRangeQuery.newFloatRange(field, (Float) min, (Float) max, minInc, minInc);
|
||||
} else if (clazz.equals(Long.class)) {
|
||||
return NumericRangeQuery.newLongRange(field, (Long) min, (Long) max, minInc, minInc);
|
||||
} else if (clazz.equals(Byte.class) || clazz.equals(Short.class)) {
|
||||
return NumericRangeQuery.newIntRange(field, min != null ? min.intValue() : null,
|
||||
max != null ? max.intValue() : null, minInc, maxInc);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported numeric type " + clazz.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private Query stringRange(String field, Expr<?> min, Expr<?> max, boolean minInc, boolean maxInc) {
|
||||
@ -293,9 +320,10 @@ public class LuceneSerializer {
|
||||
return new TermRangeQuery(field, null, normalize(createTerms(max)[0]), minInc, maxInc);
|
||||
} else if (max == null) {
|
||||
return new TermRangeQuery(field, normalize(createTerms(min)[0]), null, minInc, maxInc);
|
||||
}else{
|
||||
return new TermRangeQuery(field, normalize(createTerms(min)[0]), normalize(createTerms(max)[0]), minInc, maxInc);
|
||||
}
|
||||
} else {
|
||||
return new TermRangeQuery(field, normalize(createTerms(min)[0]),
|
||||
normalize(createTerms(max)[0]), minInc, maxInc);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -319,31 +347,32 @@ public class LuceneSerializer {
|
||||
List<Expr<?>> arguments = operation.getArgs();
|
||||
for (int i = 1; i < arguments.size(); ++i) {
|
||||
if (!(arguments.get(i) instanceof Constant<?>)
|
||||
&& !(arguments.get(i) instanceof PhraseElement)
|
||||
&& !(arguments.get(i) instanceof TermElement)) {
|
||||
throw new IllegalArgumentException("operand was of unsupported type " + arguments.get(i).getClass().getName());
|
||||
&& !(arguments.get(i) instanceof PhraseElement)
|
||||
&& !(arguments.get(i) instanceof TermElement)) {
|
||||
throw new IllegalArgumentException("operand was of unsupported type "
|
||||
+ arguments.get(i).getClass().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String[] createTerms(Expr<?> expr) {
|
||||
return split(expr, expr.toString());
|
||||
return split(expr, expr.toString());
|
||||
}
|
||||
|
||||
private String[] createEscapedTerms(Expr<?> expr) {
|
||||
return split(expr, QueryParser.escape(expr.toString()));
|
||||
}
|
||||
|
||||
private String[] split(Expr<?> expr, String str){
|
||||
if (expr instanceof PhraseElement){
|
||||
return StringUtils.split(str);
|
||||
}else if (expr instanceof TermElement){
|
||||
return new String[] {str};
|
||||
}else if (splitTerms){
|
||||
return StringUtils.split(str);
|
||||
}else{
|
||||
return new String[] {str};
|
||||
}
|
||||
|
||||
private String[] split(Expr<?> expr, String str) {
|
||||
if (expr instanceof PhraseElement) {
|
||||
return StringUtils.split(str);
|
||||
} else if (expr instanceof TermElement) {
|
||||
return new String[] { str };
|
||||
} else if (splitTerms) {
|
||||
return StringUtils.split(str);
|
||||
} else {
|
||||
return new String[] { str };
|
||||
}
|
||||
}
|
||||
|
||||
private String normalize(String s) {
|
||||
@ -356,7 +385,8 @@ public class LuceneSerializer {
|
||||
} else if (expr instanceof QueryElement) {
|
||||
return ((QueryElement) expr).getQuery();
|
||||
}
|
||||
throw new IllegalArgumentException("expr was of unsupported type " + expr.getClass().getName());
|
||||
throw new IllegalArgumentException("expr was of unsupported type "
|
||||
+ expr.getClass().getName());
|
||||
}
|
||||
|
||||
public Sort toSort(List<OrderSpecifier<?>> orderBys) {
|
||||
@ -368,9 +398,9 @@ public class LuceneSerializer {
|
||||
Class<?> type = order.getTarget().getType();
|
||||
boolean reverse = !order.isAscending();
|
||||
if (Number.class.isAssignableFrom(type)) {
|
||||
sorts.add(new SortField(toField(order.getTarget()),sortFields.get(type),reverse));
|
||||
sorts.add(new SortField(toField(order.getTarget()), sortFields.get(type), reverse));
|
||||
} else {
|
||||
sorts.add(new SortField(toField(order.getTarget()),Locale.ENGLISH, reverse));
|
||||
sorts.add(new SortField(toField(order.getTarget()), Locale.ENGLISH, reverse));
|
||||
}
|
||||
}
|
||||
Sort sort = new Sort();
|
||||
|
||||
@ -56,7 +56,7 @@ public class LuceneSerializerTest {
|
||||
private PString rating;
|
||||
private PNumber<Integer> year;
|
||||
private PNumber<Double> gross;
|
||||
|
||||
|
||||
private PNumber<Long> longField;
|
||||
private PNumber<Short> shortField;
|
||||
private PNumber<Byte> byteField;
|
||||
@ -82,7 +82,7 @@ public class LuceneSerializerTest {
|
||||
doc.add(new Field("rating", new StringReader("Good")));
|
||||
doc.add(new NumericField("year", Store.YES, true).setIntValue(1990));
|
||||
doc.add(new NumericField("gross", Store.YES, true).setDoubleValue(900.00));
|
||||
|
||||
|
||||
doc.add(new NumericField("longField", Store.YES, true).setLongValue(1));
|
||||
doc.add(new NumericField("shortField", Store.YES, true).setIntValue(1));
|
||||
doc.add(new NumericField("byteField", Store.YES, true).setIntValue(1));
|
||||
@ -102,7 +102,7 @@ public class LuceneSerializerTest {
|
||||
year = entityPath.getNumber("year", Integer.class);
|
||||
rating = entityPath.getString("rating");
|
||||
gross = entityPath.getNumber("gross", Double.class);
|
||||
|
||||
|
||||
longField = entityPath.getNumber("longField", Long.class);
|
||||
shortField = entityPath.getNumber("shortField", Short.class);
|
||||
byteField = entityPath.getNumber("byteField", Byte.class);
|
||||
@ -193,7 +193,7 @@ public class LuceneSerializerTest {
|
||||
public void eq_Numeric_Double() throws Exception {
|
||||
testQuery(gross.eq(900.00), "gross:" + GROSS_PREFIX_CODED, 1);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void eq_Numeric() throws Exception{
|
||||
testQuery(longField.eq(1l), "longField:" + LONG_PREFIX_CODED, 1);
|
||||
@ -254,7 +254,7 @@ public class LuceneSerializerTest {
|
||||
|
||||
@Test
|
||||
public void eq_not_or_eq() throws Exception {
|
||||
testQuery(title.eq("House").not().or(rating.eq("Good")), "(-title:house) rating:good", 1);
|
||||
testQuery(title.eq("House").not().or(rating.eq("Good")), "-title:house rating:good", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -264,7 +264,7 @@ public class LuceneSerializerTest {
|
||||
|
||||
@Test
|
||||
public void eq_and_eq_not_Does_Not_Find_Results_Because_Second_Expression_Finds_Nothing() throws Exception {
|
||||
testQuery(rating.eq("Superb").and(title.eq("House").not()), "+rating:superb +(-title:house)", 0);
|
||||
testQuery(rating.eq("Superb").and(title.eq("House").not()), "+rating:superb -title:house", 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -279,7 +279,7 @@ public class LuceneSerializerTest {
|
||||
|
||||
@Test
|
||||
public void ne_or_eq() throws Exception {
|
||||
testQuery(title.ne("Jurassic Park").or(rating.eq("Lousy")), "(-title:\"jurassic park\") rating:lousy", 0);
|
||||
testQuery(title.ne("Jurassic Park").or(rating.eq("Lousy")), "-title:\"jurassic park\" rating:lousy", 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -350,7 +350,7 @@ public class LuceneSerializerTest {
|
||||
testQuery(floatField.between((float)0.0,(float)2.0), "floatField:[0.0 TO 2.0]", 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void between_Phrase() throws Exception {
|
||||
testQuery(title.between("Jurassic Park", "Kundun"), "title:[jurassic TO kundun]", 1);
|
||||
@ -534,12 +534,12 @@ public class LuceneSerializerTest {
|
||||
public void goe_Numeric_Double_Not_Found() throws Exception {
|
||||
testQuery(gross.goe(900.10), "gross:[900.1 TO *]", 0);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void booleanBuilder() throws Exception{
|
||||
testQuery(new BooleanBuilder(gross.goe(900.10)), "gross:[900.1 TO *]", 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
|
||||
Loading…
Reference in New Issue
Block a user