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:
2019-04-20 19:48:51 +02:00
parent dbe0e02517
commit 56085061ed
6 changed files with 42 additions and 5 deletions

View File

@@ -5,6 +5,7 @@ import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicBoolean;
import org.lucares.collections.LongList; import org.lucares.collections.LongList;
import org.lucares.pdb.api.DateTimeRange; 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, public SortedSet<String> find(final DateTimeRange dateRange, final String property, final String value,
final String field) { final String field) {
final Tag tag = new Tag(property, value); 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); return find(dateRange, tag, field);
} }
@@ -310,4 +313,15 @@ public class QueryCompletionIndex implements AutoCloseable {
}); });
return result; 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();
}
} }

View File

@@ -42,10 +42,22 @@ public class FindValuesForQueryCompletion extends ExpressionVisitor<SortedSet<St
@Override @Override
public SortedSet<String> visit(final Property property) { public SortedSet<String> visit(final Property property) {
final long start = System.nanoTime(); final long start = System.nanoTime();
final TreeSet<String> result = new TreeSet<>();
final String fieldA = property.getProperty(); final String fieldA = property.getProperty();
final String valueA = property.getValue().getValue(); 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); METRIC_AND_CARET_LOGGER.debug("{}: {}ms", property, (System.nanoTime() - start) / 1_000_000.0);
return result; return result;
} }

View File

@@ -12,6 +12,10 @@ public class GloblikePattern {
private static final Logger LOGGER = LoggerFactory.getLogger(GloblikePattern.class); private static final Logger LOGGER = LoggerFactory.getLogger(GloblikePattern.class);
enum FilterMode {
KEEP_EQUAL
}
static Pattern globlikeToRegex(final String globPattern) { static Pattern globlikeToRegex(final String globPattern) {
// a character that cannot be in the globPattern // a character that cannot be in the globPattern
final String dotPlaceholder = "\ue003"; // fourth character in the private use area final String dotPlaceholder = "\ue003"; // fourth character in the private use area
@@ -43,7 +47,7 @@ public class GloblikePattern {
for (final String value : availableValues) { for (final String value : availableValues) {
final Matcher matcher = pattern.matcher(value); final Matcher matcher = pattern.matcher(value);
if (matcher.find() && !value.equals(valuePattern)) { if (matcher.find()) {
result.add(value); result.add(value);
} }
} }

View File

@@ -170,8 +170,7 @@ public class NewProposerParser implements QueryConstants {
final SortedSet<String> candidateValuesCutAtDots = cutAtDots(candidateValues, queryWithCaretMarker); final SortedSet<String> candidateValuesCutAtDots = cutAtDots(candidateValues, queryWithCaretMarker);
// translate the candidate values to proposals // translate the candidate values to proposals
final List<Proposal> proposals = generateProposals(queryWithCaretMarker, expression, final List<Proposal> proposals = generateProposals(queryWithCaretMarker, candidateValuesCutAtDots);
candidateValuesCutAtDots);
return proposals; return proposals;
} catch (final SyntaxException e) { } catch (final SyntaxException e) {
@@ -186,7 +185,7 @@ public class NewProposerParser implements QueryConstants {
return grouper.group(candidateValues, queryWithCaretMarker); 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 SortedSet<String> candidateValues) {
final List<Proposal> proposals = new ArrayList<>(); final List<Proposal> proposals = new ArrayList<>();

View File

@@ -165,6 +165,12 @@ public class DataStoreTest {
result.add(new Object[] { "!(type=dog and name=|) and !type=cat", "name", result.add(new Object[] { "!(type=dog and name=|) and !type=cat", "name",
Arrays.asList("Jennifer", "Jenny", "Tim") }); 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(); return result.iterator();
} }

View File

@@ -88,6 +88,7 @@ public class ProposerTest {
public void testPrefixOfValue() throws Exception { public void testPrefixOfValue() throws Exception {
assertProposals("name =Tim", 9, // assertProposals("name =Tim", 9, //
new Proposal("Tim", "name =Tim", true, "name =Tim", 9),
new Proposal("Timothy", "name =Timothy", true, "name =Timothy", 13)); new Proposal("Timothy", "name =Timothy", true, "name =Timothy", 13));
assertProposals("name =Je", 8, // assertProposals("name =Je", 8, //
@@ -116,6 +117,7 @@ public class ProposerTest {
new Proposal("Jenny", "name = (Timothy, Jenny)", true, "name = (Timothy, Jenny)", 22)); new Proposal("Jenny", "name = (Timothy, Jenny)", true, "name = (Timothy, Jenny)", 22));
assertProposals("name = (Tim)", 11, // assertProposals("name = (Tim)", 11, //
new Proposal("Tim", "name = (Tim)", true, "name = (Tim)", 11),
new Proposal("Timothy", "name = (Timothy)", true, "name = (Timothy)", 15)); new Proposal("Timothy", "name = (Timothy)", true, "name = (Timothy)", 15));
/* /*