mirror of https://github.com/apache/lucene.git
LUCENE-9659 inequality support in payload check query (#2185)
Changes from SOLR-14787 supporting inequalities in SpanPayloadCheckQuery
This commit is contained in:
parent
3b6ba9e3e8
commit
890f570bf5
|
@ -28,6 +28,7 @@ configure(project(":lucene").subprojects) { prj ->
|
|||
|
||||
spotless {
|
||||
java {
|
||||
toggleOffOn() // obviously, only to be used sparingly.
|
||||
// TODO: Work out how to support multiple different header files (we have
|
||||
// classes in the codebase that have original headers). We currently use
|
||||
// Apache RAT to enforce headers so this is of lesser priority.
|
||||
|
|
1952
lucene/CHANGES.txt
1952
lucene/CHANGES.txt
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.lucene.queries.payloads;
|
||||
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
|
||||
/** Defines an interface for testing if two payloads should be consider to match */
|
||||
public interface PayloadMatcher {
|
||||
|
||||
/**
|
||||
* This method tests if two BytesRef match.
|
||||
*
|
||||
* @param source left side of the compare
|
||||
* @param payload right side of the compare
|
||||
* @return true if the BytesRefs are matching, otherwise false.
|
||||
*/
|
||||
public boolean comparePayload(BytesRef source, BytesRef payload);
|
||||
}
|
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.lucene.queries.payloads;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.EnumMap;
|
||||
import org.apache.lucene.queries.payloads.SpanPayloadCheckQuery.MatchOperation;
|
||||
import org.apache.lucene.queries.payloads.SpanPayloadCheckQuery.PayloadType;
|
||||
import org.apache.lucene.util.ArrayUtil;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
|
||||
/**
|
||||
* Creates a payload matcher object based on a payload type and an operation. PayloadTypes of
|
||||
* INT,FLOAT, or STRING are supported. Inequality operations are supported.
|
||||
*/
|
||||
public class PayloadMatcherFactory {
|
||||
|
||||
private static final EnumMap<PayloadType, EnumMap<MatchOperation, PayloadMatcher>>
|
||||
payloadCheckerOpTypeMap;
|
||||
|
||||
static {
|
||||
payloadCheckerOpTypeMap = new EnumMap<>(PayloadType.class);
|
||||
// ints
|
||||
EnumMap<MatchOperation, PayloadMatcher> intCheckers = new EnumMap<>(MatchOperation.class);
|
||||
intCheckers.put(MatchOperation.LT, new LTIntPayloadMatcher());
|
||||
intCheckers.put(MatchOperation.LTE, new LTEIntPayloadMatcher());
|
||||
intCheckers.put(MatchOperation.GT, new GTIntPayloadMatcher());
|
||||
intCheckers.put(MatchOperation.GTE, new GTEIntPayloadMatcher());
|
||||
EnumMap<MatchOperation, PayloadMatcher> floatCheckers = new EnumMap<>(MatchOperation.class);
|
||||
floatCheckers.put(MatchOperation.LT, new LTFloatPayloadMatcher());
|
||||
floatCheckers.put(MatchOperation.LTE, new LTEFloatPayloadMatcher());
|
||||
floatCheckers.put(MatchOperation.GT, new GTFloatPayloadMatcher());
|
||||
floatCheckers.put(MatchOperation.GTE, new GTEFloatPayloadMatcher());
|
||||
// strings
|
||||
EnumMap<MatchOperation, PayloadMatcher> stringCheckers = new EnumMap<>(MatchOperation.class);
|
||||
stringCheckers.put(MatchOperation.LT, new LTStringPayloadMatcher());
|
||||
stringCheckers.put(MatchOperation.LTE, new LTEStringPayloadMatcher());
|
||||
stringCheckers.put(MatchOperation.GT, new GTStringPayloadMatcher());
|
||||
stringCheckers.put(MatchOperation.GTE, new GTEStringPayloadMatcher());
|
||||
// load the matcher maps per payload type
|
||||
payloadCheckerOpTypeMap.put(PayloadType.INT, intCheckers);
|
||||
payloadCheckerOpTypeMap.put(PayloadType.FLOAT, floatCheckers);
|
||||
payloadCheckerOpTypeMap.put(PayloadType.STRING, stringCheckers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a payload matcher for use in the SpanPayloadCheckQuery that will decode the ByteRef from
|
||||
* a payload based on the payload type, and apply a matching inequality operations
|
||||
* (eq,lt,lte,gt,and gte)
|
||||
*
|
||||
* @param payloadType the type of the payload to decode, STRING, INT, FLOAT
|
||||
* @param op and inequalit operation as the test (example: eq for equals, gt for greater than)
|
||||
* @return a payload matcher that decodes the payload and applies the operation inequality test.
|
||||
*/
|
||||
public static PayloadMatcher createMatcherForOpAndType(
|
||||
PayloadType payloadType, MatchOperation op) {
|
||||
|
||||
// special optimization, binary/byte comparison
|
||||
if (op == null || MatchOperation.EQ.equals(op)) {
|
||||
return new EQPayloadMatcher();
|
||||
}
|
||||
// otherwise, we need to pay attention to the payload type and operation
|
||||
EnumMap<MatchOperation, PayloadMatcher> opMap = payloadCheckerOpTypeMap.get(payloadType);
|
||||
if (opMap != null) {
|
||||
return opMap.get(op);
|
||||
} else {
|
||||
// Unknown op and payload type gets you an equals operator.
|
||||
return new EQPayloadMatcher();
|
||||
}
|
||||
}
|
||||
|
||||
// Equality is the same for all payload types
|
||||
private static class EQPayloadMatcher implements PayloadMatcher {
|
||||
@Override
|
||||
public boolean comparePayload(BytesRef source, BytesRef payload) {
|
||||
return source.bytesEquals(payload);
|
||||
}
|
||||
}
|
||||
|
||||
private abstract static class StringPayloadMatcher implements PayloadMatcher {
|
||||
|
||||
@Override
|
||||
public boolean comparePayload(BytesRef source, BytesRef payload) {
|
||||
return stringCompare(
|
||||
decodeString(payload.bytes, payload.offset, payload.length),
|
||||
decodeString(source.bytes, source.offset, source.length));
|
||||
}
|
||||
|
||||
private String decodeString(byte[] bytes, int offset, int length) {
|
||||
return new String(
|
||||
ArrayUtil.copyOfSubArray(bytes, offset, offset + length), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
protected abstract boolean stringCompare(String val, String threshold);
|
||||
}
|
||||
|
||||
private static class LTStringPayloadMatcher extends StringPayloadMatcher {
|
||||
|
||||
@Override
|
||||
protected boolean stringCompare(String val, String thresh) {
|
||||
int res = val.compareTo(thresh);
|
||||
return (res < 0) ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
private static class LTEStringPayloadMatcher extends StringPayloadMatcher {
|
||||
|
||||
@Override
|
||||
protected boolean stringCompare(String val, String thresh) {
|
||||
int res = val.compareTo(thresh);
|
||||
return (res < 1) ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
private static class GTStringPayloadMatcher extends StringPayloadMatcher {
|
||||
|
||||
@Override
|
||||
protected boolean stringCompare(String val, String thresh) {
|
||||
int res = val.compareTo(thresh);
|
||||
return (res > 0) ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
private static class GTEStringPayloadMatcher extends StringPayloadMatcher {
|
||||
|
||||
@Override
|
||||
protected boolean stringCompare(String val, String thresh) {
|
||||
int res = val.compareTo(thresh);
|
||||
return (res > -1) ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
private abstract static class IntPayloadMatcher implements PayloadMatcher {
|
||||
|
||||
@Override
|
||||
public boolean comparePayload(BytesRef source, BytesRef payload) {
|
||||
return intCompare(
|
||||
decodeInt(payload.bytes, payload.offset), decodeInt(source.bytes, source.offset));
|
||||
}
|
||||
|
||||
private int decodeInt(byte[] bytes, int offset) {
|
||||
return ((bytes[offset] & 0xFF) << 24)
|
||||
| ((bytes[offset + 1] & 0xFF) << 16)
|
||||
| ((bytes[offset + 2] & 0xFF) << 8)
|
||||
| (bytes[offset + 3] & 0xFF);
|
||||
}
|
||||
|
||||
protected abstract boolean intCompare(int val, int threshold);
|
||||
}
|
||||
|
||||
private static class LTIntPayloadMatcher extends IntPayloadMatcher {
|
||||
|
||||
@Override
|
||||
public boolean intCompare(int val, int thresh) {
|
||||
return (val < thresh);
|
||||
}
|
||||
}
|
||||
|
||||
private static class LTEIntPayloadMatcher extends IntPayloadMatcher {
|
||||
|
||||
@Override
|
||||
public boolean intCompare(int val, int thresh) {
|
||||
return (val <= thresh);
|
||||
}
|
||||
}
|
||||
|
||||
private static class GTIntPayloadMatcher extends IntPayloadMatcher {
|
||||
|
||||
@Override
|
||||
public boolean intCompare(int val, int thresh) {
|
||||
return (val > thresh);
|
||||
}
|
||||
}
|
||||
|
||||
private static class GTEIntPayloadMatcher extends IntPayloadMatcher {
|
||||
|
||||
@Override
|
||||
protected boolean intCompare(int val, int thresh) {
|
||||
return (val >= thresh);
|
||||
}
|
||||
}
|
||||
|
||||
private abstract static class FloatPayloadMatcher implements PayloadMatcher {
|
||||
|
||||
@Override
|
||||
public boolean comparePayload(BytesRef source, BytesRef payload) {
|
||||
return floatCompare(
|
||||
decodeFloat(payload.bytes, payload.offset), decodeFloat(source.bytes, source.offset));
|
||||
}
|
||||
|
||||
private float decodeFloat(byte[] bytes, int offset) {
|
||||
return Float.intBitsToFloat(
|
||||
((bytes[offset] & 0xFF) << 24)
|
||||
| ((bytes[offset + 1] & 0xFF) << 16)
|
||||
| ((bytes[offset + 2] & 0xFF) << 8)
|
||||
| (bytes[offset + 3] & 0xFF));
|
||||
}
|
||||
|
||||
protected abstract boolean floatCompare(float val, float threshold);
|
||||
}
|
||||
|
||||
private static class LTFloatPayloadMatcher extends FloatPayloadMatcher {
|
||||
|
||||
@Override
|
||||
protected boolean floatCompare(float val, float thresh) {
|
||||
return (val < thresh);
|
||||
}
|
||||
}
|
||||
|
||||
private static class LTEFloatPayloadMatcher extends FloatPayloadMatcher {
|
||||
|
||||
@Override
|
||||
protected boolean floatCompare(float val, float thresh) {
|
||||
return (val <= thresh);
|
||||
}
|
||||
}
|
||||
|
||||
private static class GTFloatPayloadMatcher extends FloatPayloadMatcher {
|
||||
|
||||
@Override
|
||||
protected boolean floatCompare(float val, float thresh) {
|
||||
return (val > thresh);
|
||||
}
|
||||
}
|
||||
|
||||
private static class GTEFloatPayloadMatcher extends FloatPayloadMatcher {
|
||||
|
||||
@Override
|
||||
protected boolean floatCompare(float val, float thresh) {
|
||||
return (val >= thresh);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -46,14 +46,56 @@ public class SpanPayloadCheckQuery extends SpanQuery {
|
|||
|
||||
protected final List<BytesRef> payloadToMatch;
|
||||
protected final SpanQuery match;
|
||||
protected final MatchOperation operation;
|
||||
protected final PayloadType payloadType;
|
||||
/** The payload type. This specifies the decoding of the ByteRef for the payload. */
|
||||
public static enum PayloadType {
|
||||
/** INT is for a 4 byte payload that is a packed integer */
|
||||
INT,
|
||||
/** FLOAT is a 4 byte payload decoded to a float(32bit). */
|
||||
FLOAT,
|
||||
/** STRING is a UTF8 encoded string, decoded from the byte array */
|
||||
STRING
|
||||
};
|
||||
|
||||
/** The payload type. This specifies the decoding of the ByteRef for the payload. */
|
||||
public static enum MatchOperation {
|
||||
/** Checks for binary equality of the byte array (default) */
|
||||
EQ,
|
||||
/** GT Matches if the payload value is greater than the reference */
|
||||
GT,
|
||||
/** GTE Matches if the payload value is greater than or equal to the reference */
|
||||
GTE,
|
||||
/** LT Matches if the payload value is less than the reference */
|
||||
LT,
|
||||
/** LTE Matches if the payload value is less than or equal to the reference */
|
||||
LTE
|
||||
};
|
||||
|
||||
/**
|
||||
* @param match The underlying {@link org.apache.lucene.search.spans.SpanQuery} to check
|
||||
* @param payloadToMatch The {@link java.util.List} of payloads to match
|
||||
*/
|
||||
public SpanPayloadCheckQuery(SpanQuery match, List<BytesRef> payloadToMatch) {
|
||||
this(match, payloadToMatch, PayloadType.STRING, MatchOperation.EQ);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param match The underlying {@link org.apache.lucene.search.spans.SpanQuery} to check
|
||||
* @param payloadToMatch The {@link java.util.List} of payloads to match
|
||||
* @param operation The equality check, lt, lte, gt, gte, or eq. Defaults to eq for equals)
|
||||
* @param payloadType specify if the format of the bytes in the payload (String, Integer, or
|
||||
* Float)
|
||||
*/
|
||||
public SpanPayloadCheckQuery(
|
||||
SpanQuery match,
|
||||
List<BytesRef> payloadToMatch,
|
||||
PayloadType payloadType,
|
||||
MatchOperation operation) {
|
||||
this.match = match;
|
||||
this.payloadToMatch = payloadToMatch;
|
||||
this.payloadType = payloadType;
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -66,14 +108,19 @@ public class SpanPayloadCheckQuery extends SpanQuery {
|
|||
throws IOException {
|
||||
SpanWeight matchWeight = match.createWeight(searcher, scoreMode, boost);
|
||||
return new SpanPayloadCheckWeight(
|
||||
searcher, scoreMode.needsScores() ? getTermStates(matchWeight) : null, matchWeight, boost);
|
||||
searcher,
|
||||
scoreMode.needsScores() ? getTermStates(matchWeight) : null,
|
||||
matchWeight,
|
||||
boost,
|
||||
payloadType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query rewrite(IndexReader reader) throws IOException {
|
||||
Query matchRewritten = match.rewrite(reader);
|
||||
if (match != matchRewritten && matchRewritten instanceof SpanQuery) {
|
||||
return new SpanPayloadCheckQuery((SpanQuery) matchRewritten, payloadToMatch);
|
||||
return new SpanPayloadCheckQuery(
|
||||
(SpanQuery) matchRewritten, payloadToMatch, payloadType, operation);
|
||||
}
|
||||
return super.rewrite(reader);
|
||||
}
|
||||
|
@ -94,7 +141,8 @@ public class SpanPayloadCheckQuery extends SpanQuery {
|
|||
IndexSearcher searcher,
|
||||
Map<Term, TermStates> termStates,
|
||||
SpanWeight matchWeight,
|
||||
float boost)
|
||||
float boost,
|
||||
PayloadType payloadType)
|
||||
throws IOException {
|
||||
super(SpanPayloadCheckQuery.this, searcher, termStates, boost);
|
||||
this.matchWeight = matchWeight;
|
||||
|
@ -154,8 +202,10 @@ public class SpanPayloadCheckQuery extends SpanQuery {
|
|||
|
||||
private class PayloadChecker implements SpanCollector {
|
||||
|
||||
int upto = 0;
|
||||
boolean matches = true;
|
||||
private int upto = 0;
|
||||
private boolean matches = true;
|
||||
private final PayloadMatcher payloadMatcher =
|
||||
PayloadMatcherFactory.createMatcherForOpAndType(payloadType, operation);
|
||||
|
||||
@Override
|
||||
public void collectLeaf(PostingsEnum postings, int position, Term term) throws IOException {
|
||||
|
@ -177,7 +227,7 @@ public class SpanPayloadCheckQuery extends SpanQuery {
|
|||
upto++;
|
||||
return;
|
||||
}
|
||||
matches = payloadToMatch.get(upto).bytesEquals(payload);
|
||||
matches = payloadMatcher.comparePayload(payloadToMatch.get(upto), payload);
|
||||
upto++;
|
||||
}
|
||||
|
||||
|
@ -202,15 +252,20 @@ public class SpanPayloadCheckQuery extends SpanQuery {
|
|||
buffer.append(Term.toString(bytes));
|
||||
buffer.append(';');
|
||||
}
|
||||
buffer.append(", payloadType:").append(payloadType).append(";");
|
||||
buffer.append(", operation:").append(operation).append(";");
|
||||
buffer.append(")");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
@SuppressWarnings("EqualsWhichDoesntCheckParameterClass") // it does but ides are easily confused
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return sameClassAs(other)
|
||||
&& payloadToMatch.equals(((SpanPayloadCheckQuery) other).payloadToMatch)
|
||||
&& match.equals(((SpanPayloadCheckQuery) other).match);
|
||||
&& match.equals(((SpanPayloadCheckQuery) other).match)
|
||||
&& operation.equals(((SpanPayloadCheckQuery) other).operation)
|
||||
&& payloadType.equals(((SpanPayloadCheckQuery) other).payloadType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -218,6 +273,8 @@ public class SpanPayloadCheckQuery extends SpanQuery {
|
|||
int result = classHash();
|
||||
result = 31 * result + Objects.hashCode(match);
|
||||
result = 31 * result + Objects.hashCode(payloadToMatch);
|
||||
result = 31 * result + Objects.hashCode(operation);
|
||||
result = 31 * result + Objects.hashCode(payloadType);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
219
lucene/queries/src/test/org/apache/lucene/queries/payloads/TestPayloadCheckQuery.java
Normal file → Executable file
219
lucene/queries/src/test/org/apache/lucene/queries/payloads/TestPayloadCheckQuery.java
Normal file → Executable file
|
@ -17,8 +17,10 @@
|
|||
package org.apache.lucene.queries.payloads;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.apache.lucene.analysis.Analyzer;
|
||||
|
@ -30,6 +32,8 @@ import org.apache.lucene.document.Field;
|
|||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.index.RandomIndexWriter;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.queries.payloads.SpanPayloadCheckQuery.MatchOperation;
|
||||
import org.apache.lucene.queries.payloads.SpanPayloadCheckQuery.PayloadType;
|
||||
import org.apache.lucene.search.CheckHits;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.search.Query;
|
||||
|
@ -152,6 +156,156 @@ public class TestPayloadCheckQuery extends LuceneTestCase {
|
|||
checkHits(query, new int[] {505});
|
||||
}
|
||||
|
||||
public void testInequalityPayloadChecks() throws Exception {
|
||||
// searching for the term five with a payload of either "pos: 0" or a payload of "pos: 1"
|
||||
SpanQuery termFive = new SpanTermQuery(new Term("field", "five"));
|
||||
SpanQuery termFifty = new SpanTermQuery(new Term("field", "fifty"));
|
||||
BytesRef payloadZero = new BytesRef("pos: " + 0);
|
||||
BytesRef payloadOne = new BytesRef("pos: " + 1);
|
||||
BytesRef payloadTwo = new BytesRef("pos: " + 2);
|
||||
BytesRef payloadThree = new BytesRef("pos: " + 3);
|
||||
BytesRef payloadFour = new BytesRef("pos: " + 4);
|
||||
BytesRef payloadFive = new BytesRef("pos: " + 5);
|
||||
// Terms that equal five with a payload of "pos: 1"
|
||||
SpanQuery stringEQ1 =
|
||||
new SpanPayloadCheckQuery(
|
||||
termFive,
|
||||
Collections.singletonList(payloadOne),
|
||||
SpanPayloadCheckQuery.PayloadType.STRING,
|
||||
MatchOperation.EQ);
|
||||
checkHits(stringEQ1, new int[] {25, 35, 45, 55, 65, 75, 85, 95});
|
||||
|
||||
// These queries return the same thing
|
||||
SpanQuery stringLT =
|
||||
new SpanPayloadCheckQuery(
|
||||
termFive,
|
||||
Collections.singletonList(payloadOne),
|
||||
SpanPayloadCheckQuery.PayloadType.STRING,
|
||||
MatchOperation.LT);
|
||||
SpanQuery stringLTE =
|
||||
new SpanPayloadCheckQuery(
|
||||
termFive,
|
||||
Collections.singletonList(payloadZero),
|
||||
SpanPayloadCheckQuery.PayloadType.STRING,
|
||||
MatchOperation.LTE);
|
||||
// string less than and string less than or equal
|
||||
checkHits(
|
||||
stringLT,
|
||||
new int[] {
|
||||
5, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516,
|
||||
517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534,
|
||||
535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552,
|
||||
553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570,
|
||||
571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588,
|
||||
589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599
|
||||
});
|
||||
checkHits(
|
||||
stringLTE,
|
||||
new int[] {
|
||||
5, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516,
|
||||
517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534,
|
||||
535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552,
|
||||
553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570,
|
||||
571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588,
|
||||
589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599
|
||||
});
|
||||
// greater than and greater than or equal tests.
|
||||
SpanQuery stringGT =
|
||||
new SpanPayloadCheckQuery(
|
||||
termFive,
|
||||
Collections.singletonList(payloadFour),
|
||||
SpanPayloadCheckQuery.PayloadType.STRING,
|
||||
MatchOperation.GT);
|
||||
SpanQuery stringGTE =
|
||||
new SpanPayloadCheckQuery(
|
||||
termFive,
|
||||
Collections.singletonList(payloadFive),
|
||||
SpanPayloadCheckQuery.PayloadType.STRING,
|
||||
MatchOperation.GTE);
|
||||
checkHits(
|
||||
stringGT,
|
||||
new int[] {
|
||||
1125, 1135, 1145, 1155, 1165, 1175, 1185, 1195, 1225, 1235, 1245, 1255, 1265, 1275, 1285,
|
||||
1295, 1325, 1335, 1345, 1355, 1365, 1375, 1385, 1395, 1425, 1435, 1445, 1455, 1465, 1475,
|
||||
1485, 1495, 1525, 1535, 1545, 1555, 1565, 1575, 1585, 1595, 1625, 1635, 1645, 1655, 1665,
|
||||
1675, 1685, 1695, 1725, 1735, 1745, 1755, 1765, 1775, 1785, 1795, 1825, 1835, 1845, 1855,
|
||||
1865, 1875, 1885, 1895, 1925, 1935, 1945, 1955, 1965, 1975, 1985, 1995
|
||||
});
|
||||
checkHits(
|
||||
stringGTE,
|
||||
new int[] {
|
||||
1125, 1135, 1145, 1155, 1165, 1175, 1185, 1195, 1225, 1235, 1245, 1255, 1265, 1275, 1285,
|
||||
1295, 1325, 1335, 1345, 1355, 1365, 1375, 1385, 1395, 1425, 1435, 1445, 1455, 1465, 1475,
|
||||
1485, 1495, 1525, 1535, 1545, 1555, 1565, 1575, 1585, 1595, 1625, 1635, 1645, 1655, 1665,
|
||||
1675, 1685, 1695, 1725, 1735, 1745, 1755, 1765, 1775, 1785, 1795, 1825, 1835, 1845, 1855,
|
||||
1865, 1875, 1885, 1895, 1925, 1935, 1945, 1955, 1965, 1975, 1985, 1995
|
||||
});
|
||||
|
||||
// now a not so happy path...
|
||||
SpanQuery stringEQ2many =
|
||||
new SpanPayloadCheckQuery(
|
||||
termFive,
|
||||
Arrays.asList(payloadOne, payloadZero),
|
||||
SpanPayloadCheckQuery.PayloadType.STRING,
|
||||
MatchOperation.EQ);
|
||||
// fewer terms than payloads should not match anything, one wonders if this should be an error,
|
||||
// but it's been explicitly ignored previously, so changing it is a possible back compat issue.
|
||||
checkHits(stringEQ2many, new int[] {});
|
||||
|
||||
// now some straight forward two term cases...
|
||||
SpanQuery stringEQ2 =
|
||||
new SpanPayloadCheckQuery(
|
||||
new SpanNearQuery(new SpanQuery[] {termFifty, termFive}, 0, true),
|
||||
Arrays.asList(payloadZero, payloadOne),
|
||||
SpanPayloadCheckQuery.PayloadType.STRING,
|
||||
MatchOperation.EQ);
|
||||
checkHits(stringEQ2, new int[] {55});
|
||||
|
||||
SpanQuery stringGT2 =
|
||||
new SpanPayloadCheckQuery(
|
||||
new SpanNearQuery(new SpanQuery[] {termFifty, termFive}, 0, true),
|
||||
Arrays.asList(payloadZero, payloadOne),
|
||||
SpanPayloadCheckQuery.PayloadType.STRING,
|
||||
MatchOperation.GT);
|
||||
checkHits(
|
||||
stringGT2,
|
||||
new int[] { // spotless:off
|
||||
55, 155, 255, 355, 455, 555, 655, 755, 855, 955,
|
||||
1055, 1155, 1255, 1355, 1455, 1555, 1655, 1755, 1855, 1955
|
||||
}); // spotless:on
|
||||
SpanQuery stringGTE2 =
|
||||
new SpanPayloadCheckQuery(
|
||||
new SpanNearQuery(new SpanQuery[] {termFifty, termFive}, 0, true),
|
||||
Arrays.asList(payloadZero, payloadOne),
|
||||
SpanPayloadCheckQuery.PayloadType.STRING,
|
||||
MatchOperation.GTE);
|
||||
checkHits(
|
||||
stringGTE2,
|
||||
new int[] { // spotless:off
|
||||
55, 155, 255, 355, 455, 555, 655, 755, 855, 955,
|
||||
1055, 1155, 1255, 1355, 1455, 1555, 1655, 1755, 1855, 1955
|
||||
}); // spotless:on
|
||||
|
||||
SpanQuery stringLT2 =
|
||||
new SpanPayloadCheckQuery(
|
||||
new SpanNearQuery(new SpanQuery[] {termFifty, termFive}, 0, true),
|
||||
Arrays.asList(payloadTwo, payloadThree),
|
||||
SpanPayloadCheckQuery.PayloadType.STRING,
|
||||
MatchOperation.LT);
|
||||
checkHits(stringLT2, new int[] {55});
|
||||
SpanQuery stringLTE2 =
|
||||
new SpanPayloadCheckQuery(
|
||||
new SpanNearQuery(new SpanQuery[] {termFifty, termFive}, 0, true),
|
||||
Arrays.asList(payloadTwo, payloadThree),
|
||||
SpanPayloadCheckQuery.PayloadType.STRING,
|
||||
MatchOperation.LTE);
|
||||
checkHits(stringLTE2, new int[] {55, 155, 255, 355, 455, 555, 655, 755, 855, 955, 1055});
|
||||
|
||||
// note: I can imagine support for SpanOrQuery might be interesting but that's for some other
|
||||
// time, currently such support is made intractable by the fact that reset() gets called and
|
||||
// sets "upto" back to zero between SpanOrQuery subclauses.
|
||||
}
|
||||
|
||||
public void testUnorderedPayloadChecks() throws Exception {
|
||||
|
||||
SpanTermQuery term5 = new SpanTermQuery(new Term("field", "five"));
|
||||
|
@ -226,6 +380,71 @@ public class TestPayloadCheckQuery extends LuceneTestCase {
|
|||
assertFalse(query2.equals(query3));
|
||||
assertFalse(query2.equals(query4));
|
||||
assertFalse(query3.equals(query4));
|
||||
|
||||
// Create an integer and a float encoded payload
|
||||
Integer i = 451;
|
||||
BytesRef intPayload = new BytesRef(ByteBuffer.allocate(4).putInt(i).array());
|
||||
Float e = 2.71828f;
|
||||
BytesRef floatPayload = new BytesRef(ByteBuffer.allocate(4).putFloat(e).array());
|
||||
SpanQuery floatLTQuery =
|
||||
new SpanPayloadCheckQuery(
|
||||
sq1, Collections.singletonList(floatPayload), PayloadType.FLOAT, MatchOperation.LT);
|
||||
SpanQuery floatLTEQuery =
|
||||
new SpanPayloadCheckQuery(
|
||||
sq1, Collections.singletonList(floatPayload), PayloadType.FLOAT, MatchOperation.LTE);
|
||||
SpanQuery floatGTQuery =
|
||||
new SpanPayloadCheckQuery(
|
||||
sq1, Collections.singletonList(floatPayload), PayloadType.FLOAT, MatchOperation.GT);
|
||||
SpanQuery floatGTEQuery =
|
||||
new SpanPayloadCheckQuery(
|
||||
sq1, Collections.singletonList(floatPayload), PayloadType.FLOAT, MatchOperation.GTE);
|
||||
|
||||
SpanQuery intLTQuery =
|
||||
new SpanPayloadCheckQuery(
|
||||
sq1, Collections.singletonList(intPayload), PayloadType.INT, MatchOperation.LT);
|
||||
SpanQuery intLTEQuery =
|
||||
new SpanPayloadCheckQuery(
|
||||
sq1, Collections.singletonList(intPayload), PayloadType.INT, MatchOperation.LTE);
|
||||
SpanQuery intGTQuery =
|
||||
new SpanPayloadCheckQuery(
|
||||
sq1, Collections.singletonList(intPayload), PayloadType.INT, MatchOperation.GT);
|
||||
SpanQuery intGTEQuery =
|
||||
new SpanPayloadCheckQuery(
|
||||
sq1, Collections.singletonList(intPayload), PayloadType.INT, MatchOperation.GT);
|
||||
|
||||
// string inequality checks
|
||||
SpanQuery stringLTQuery =
|
||||
new SpanPayloadCheckQuery(
|
||||
sq1, Collections.singletonList(intPayload), PayloadType.STRING, MatchOperation.LT);
|
||||
SpanQuery stringLTEQuery =
|
||||
new SpanPayloadCheckQuery(
|
||||
sq1, Collections.singletonList(intPayload), PayloadType.STRING, MatchOperation.LTE);
|
||||
SpanQuery stringGTQuery =
|
||||
new SpanPayloadCheckQuery(
|
||||
sq1, Collections.singletonList(intPayload), PayloadType.STRING, MatchOperation.GT);
|
||||
SpanQuery stringGTEQuery =
|
||||
new SpanPayloadCheckQuery(
|
||||
sq1, Collections.singletonList(intPayload), PayloadType.STRING, MatchOperation.GT);
|
||||
SpanQuery stringEQQuery =
|
||||
new SpanPayloadCheckQuery(
|
||||
sq1, Collections.singletonList(intPayload), PayloadType.STRING, MatchOperation.EQ);
|
||||
|
||||
SpanQuery stringDefaultQuery =
|
||||
new SpanPayloadCheckQuery(sq1, Collections.singletonList(intPayload));
|
||||
|
||||
assertTrue(stringDefaultQuery.equals(stringEQQuery));
|
||||
assertFalse(stringDefaultQuery.equals(stringGTQuery));
|
||||
assertFalse(stringDefaultQuery.equals(stringGTEQuery));
|
||||
assertFalse(stringDefaultQuery.equals(stringLTQuery));
|
||||
assertFalse(stringDefaultQuery.equals(stringLTEQuery));
|
||||
|
||||
assertFalse(floatLTQuery.equals(floatLTEQuery));
|
||||
assertFalse(floatLTQuery.equals(floatGTQuery));
|
||||
assertFalse(floatLTQuery.equals(floatGTEQuery));
|
||||
assertFalse(floatLTQuery.equals(intLTQuery));
|
||||
assertFalse(floatLTQuery.equals(intLTEQuery));
|
||||
assertFalse(floatLTQuery.equals(intGTQuery));
|
||||
assertFalse(floatLTQuery.equals(intGTEQuery));
|
||||
}
|
||||
|
||||
public void testRewrite() throws IOException {
|
||||
|
|
Loading…
Reference in New Issue