do not return anything if the field/value does not exist
The computation of proposals is done by searching for values in a combined index. If one of the values didn't exist, then the algorithm returned all values. Fixed by checking that we query only existing field/values from the combined index.
This commit is contained in:
@@ -5,6 +5,7 @@ import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.lucares.collections.LongList;
|
||||
import org.lucares.pdb.api.DateTimeRange;
|
||||
@@ -250,6 +251,8 @@ public class QueryCompletionIndex implements AutoCloseable {
|
||||
public SortedSet<String> find(final DateTimeRange dateRange, final String property, final String value,
|
||||
final String field) {
|
||||
final Tag tag = new Tag(property, value);
|
||||
Preconditions.checkGreaterOrEqual(tag.getKey(), 0, "The property '{0}' is unkown", property);
|
||||
Preconditions.checkGreaterOrEqual(tag.getValue(), 0, "The value '{0}' is unkown", value);
|
||||
return find(dateRange, tag, field);
|
||||
}
|
||||
|
||||
@@ -310,4 +313,15 @@ public class QueryCompletionIndex implements AutoCloseable {
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean hasField(final DateTimeRange dateRange, final String field) {
|
||||
final AtomicBoolean found = new AtomicBoolean(false);
|
||||
final PartitionIdSource partitionIdSource = new DatePartitioner(dateRange);
|
||||
fieldIndex.visitValues(partitionIdSource, "", (k, v) -> {
|
||||
if (k.equals(field)) {
|
||||
found.set(true);
|
||||
}
|
||||
});
|
||||
return found.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,10 +42,22 @@ public class FindValuesForQueryCompletion extends ExpressionVisitor<SortedSet<St
|
||||
@Override
|
||||
public SortedSet<String> visit(final Property property) {
|
||||
final long start = System.nanoTime();
|
||||
final TreeSet<String> result = new TreeSet<>();
|
||||
|
||||
final String fieldA = property.getProperty();
|
||||
final String valueA = property.getValue().getValue();
|
||||
|
||||
final SortedSet<String> result = index.find(dateTimeRange, fieldA, valueA, field);
|
||||
final boolean hasField = index.hasField(dateTimeRange, fieldA);
|
||||
if (hasField) {
|
||||
final SortedSet<String> allValuesForField = index.findAllValuesForField(dateTimeRange, fieldA);
|
||||
final SortedSet<String> valuesA = GloblikePattern.filterValues(allValuesForField, valueA, TreeSet::new);
|
||||
|
||||
for (final String v : valuesA) {
|
||||
final SortedSet<String> tmp = index.find(dateTimeRange, fieldA, v, field);
|
||||
result.addAll(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
METRIC_AND_CARET_LOGGER.debug("{}: {}ms", property, (System.nanoTime() - start) / 1_000_000.0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,10 @@ public class GloblikePattern {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(GloblikePattern.class);
|
||||
|
||||
enum FilterMode {
|
||||
KEEP_EQUAL
|
||||
}
|
||||
|
||||
static Pattern globlikeToRegex(final String globPattern) {
|
||||
// a character that cannot be in the globPattern
|
||||
final String dotPlaceholder = "\ue003"; // fourth character in the private use area
|
||||
@@ -43,7 +47,7 @@ public class GloblikePattern {
|
||||
|
||||
for (final String value : availableValues) {
|
||||
final Matcher matcher = pattern.matcher(value);
|
||||
if (matcher.find() && !value.equals(valuePattern)) {
|
||||
if (matcher.find()) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,8 +170,7 @@ public class NewProposerParser implements QueryConstants {
|
||||
final SortedSet<String> candidateValuesCutAtDots = cutAtDots(candidateValues, queryWithCaretMarker);
|
||||
|
||||
// translate the candidate values to proposals
|
||||
final List<Proposal> proposals = generateProposals(queryWithCaretMarker, expression,
|
||||
candidateValuesCutAtDots);
|
||||
final List<Proposal> proposals = generateProposals(queryWithCaretMarker, candidateValuesCutAtDots);
|
||||
|
||||
return proposals;
|
||||
} catch (final SyntaxException e) {
|
||||
@@ -186,7 +185,7 @@ public class NewProposerParser implements QueryConstants {
|
||||
return grouper.group(candidateValues, queryWithCaretMarker);
|
||||
}
|
||||
|
||||
private List<Proposal> generateProposals(final String queryWithCaretMarker, final Expression expression,
|
||||
private List<Proposal> generateProposals(final String queryWithCaretMarker,
|
||||
final SortedSet<String> candidateValues) {
|
||||
final List<Proposal> proposals = new ArrayList<>();
|
||||
|
||||
|
||||
@@ -165,6 +165,12 @@ public class DataStoreTest {
|
||||
result.add(new Object[] { "!(type=dog and name=|) and !type=cat", "name",
|
||||
Arrays.asList("Jennifer", "Jenny", "Tim") });
|
||||
|
||||
// not existing field
|
||||
result.add(new Object[] { "name=| and XYZ=Tim", "name", Arrays.asList() });
|
||||
|
||||
// not existing value
|
||||
result.add(new Object[] { "name=| and type=XYZ", "name", Arrays.asList() });
|
||||
|
||||
return result.iterator();
|
||||
}
|
||||
|
||||
|
||||
@@ -88,6 +88,7 @@ public class ProposerTest {
|
||||
|
||||
public void testPrefixOfValue() throws Exception {
|
||||
assertProposals("name =Tim", 9, //
|
||||
new Proposal("Tim", "name =Tim", true, "name =Tim", 9),
|
||||
new Proposal("Timothy", "name =Timothy", true, "name =Timothy", 13));
|
||||
|
||||
assertProposals("name =Je", 8, //
|
||||
@@ -116,6 +117,7 @@ public class ProposerTest {
|
||||
new Proposal("Jenny", "name = (Timothy, Jenny)", true, "name = (Timothy, Jenny)", 22));
|
||||
|
||||
assertProposals("name = (Tim)", 11, //
|
||||
new Proposal("Tim", "name = (Tim)", true, "name = (Tim)", 11),
|
||||
new Proposal("Timothy", "name = (Timothy)", true, "name = (Timothy)", 15));
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user