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.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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<>();
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user