remove obsolete classes

This commit is contained in:
2019-02-02 16:45:34 +01:00
parent 76e5d441de
commit 151e9363e1
4 changed files with 0 additions and 509 deletions

View File

@@ -1,58 +0,0 @@
package org.lucares.pdb.datastore.internal;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import org.apache.commons.lang3.StringUtils;
import org.lucares.pdb.datastore.Proposal;
import org.lucares.pdb.datastore.lang.ProposerParser;
import org.lucares.utils.CollectionUtils;
public class Proposer {
/**
* We are using an AntLR parser to find the right proposals. But that approach
* does not work if a terminal is empty. The parser does not recognize missing
* terminals.
* <p>
* The hack-around is to add a marker character that helps the parser to find
* the terminal.
*/
public static final String PREFIX_MARKER = "\ue001"; // second character in the private use area
private final DataStore dataStore;
public Proposer(final DataStore dataStore) {
this.dataStore = dataStore;
}
public List<Proposal> propose(final String query, final int caretIndex) {
final SortedSet<Proposal> result;
if (StringUtils.isBlank(query)) {
result = proposeForAllKeys();
} else {
final StringBuilder q = new StringBuilder(query);
q.insert(caretIndex, PREFIX_MARKER);
result = ProposerParser.parse(q.toString(), dataStore, caretIndex + 1);
}
return CollectionUtils.filter(result, Proposal::hasResults);
}
private SortedSet<Proposal> proposeForAllKeys() {
final SortedSet<Proposal> result = new TreeSet<>();
final List<String> fields = dataStore.getAvailableFields();
for (final String field : fields) {
final String newQuery = field + "=";
final Proposal proposal = new Proposal(field, field + "=*", true, newQuery, newQuery.length());
result.add(proposal);
}
return result;
}
}

View File

@@ -1,39 +0,0 @@
package org.lucares.pdb.datastore.lang;
import java.util.SortedSet;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.lucares.pdb.datastore.Proposal;
import org.lucares.pdb.datastore.internal.DataStore;
import org.lucares.pdb.datastore.lang.QueryCompletionPdbLangParser.Listener;
public class ProposerParser {
public static SortedSet<Proposal> parse(final String query, final DataStore dataStore, final int caretIndex) {
final ProposerParser lang = new ProposerParser();
return lang.parseInternal(query, dataStore, caretIndex);
}
private SortedSet<Proposal> parseInternal(final String query, final DataStore dataStore, final int caretIndex) {
final CharStream in = CharStreams.fromString(query);
final PdbLangLexer lexer = new PdbLangLexer(in);
final CommonTokenStream tokens = new CommonTokenStream(lexer);
final QueryCompletionPdbLangParser parser = new QueryCompletionPdbLangParser(tokens);
parser.setTrace(false);
final Listener listener = parser.new Listener(query, dataStore, caretIndex);
parser.addErrorListener(listener);
parser.addParseListener(listener);
parser.start();
return listener.getProposals();
}
}

View File

@@ -1,329 +0,0 @@
package org.lucares.pdb.datastore.lang;
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.antlr.v4.runtime.ANTLRErrorListener;
import org.antlr.v4.runtime.CommonToken;
import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Recognizer;
import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.atn.ATNConfigSet;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.lucares.pdb.datastore.Proposal;
import org.lucares.pdb.datastore.internal.DataStore;
import org.lucares.pdb.datastore.internal.Proposer;
import org.lucares.utils.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class QueryCompletionPdbLangParser extends PdbLangParser {
private final static String CARET_MARKER = "\ue002"; // third character in the private use area
private static final Logger METRICS_LOGGER = LoggerFactory.getLogger("org.lucares.metrics.autocomplete");
public class Listener implements PdbLangListener, ANTLRErrorListener {
private final int caretPosition;
private final DataStore dataStore;
private final SortedSet<Proposal> proposals = Collections.synchronizedSortedSet(new TreeSet<>());
private final String query;
public Listener(final String query, final DataStore dataStore, final int caretPosition) {
this.query = query;
this.dataStore = dataStore;
this.caretPosition = caretPosition;
}
public SortedSet<Proposal> getProposals() {
return proposals;
}
@Override
public void visitTerminal(final TerminalNode node) {
if (containsCaret(node) && !isEOF(node)) {
final int start = node.getSymbol().getStartIndex();
final int end = node.getSymbol().getStopIndex();
if (_ctx instanceof PropertyTerminalExpressionContext) {
final String postfixAfterInsertedTerminal;
final String propertyKey;
if (_ctx.getParent() instanceof ListOfPropValuesContext) {
// for in-expressions, e.g. key in (val)
ParserRuleContext parent = _ctx.getParent();
while (parent instanceof ListOfPropValuesContext
|| parent instanceof EnclosedListOfPropValuesContext) {
parent = parent.getParent();
}
propertyKey = parent.children.get(0).getText();
postfixAfterInsertedTerminal = "";
} else {
// for property-expressions, e.g. key = val
propertyKey = _ctx.getParent().children.get(0).getText();
postfixAfterInsertedTerminal = " ";
}
String propertyValuePrefix = node.getText().substring(0, caretPosition - start);
propertyValuePrefix = propertyValuePrefix.replace(Proposer.PREFIX_MARKER, "");
final SortedSet<String> proposedValues = getPropertyValuesByPrefix(propertyKey,
propertyValuePrefix);
final long startTime = System.nanoTime();
proposedValues.stream()//
.map(v -> {
final StringBuilder newQuery = new StringBuilder(query);
newQuery.replace(start, end + 1, v + postfixAfterInsertedTerminal); // insert the
// terminal into the
// query
return new Proposal(v, newQuery.toString(), false, newQuery.toString(),
start + v.length() + postfixAfterInsertedTerminal.length());
}).map(p -> {
int count = 0;
try {
count = dataStore.count(p.getProposedQuery());
} catch (final SyntaxException e) {
// ignore: if the query is not valid, then it does not find any results
}
return new Proposal(p, count > 0);
}).forEach(proposals::add);
METRICS_LOGGER.debug("proposals for property value {} took {} ms", propertyValuePrefix,
(System.nanoTime() - startTime) / 1_000_000.0);
} else if (_ctx instanceof IdentifierExpressionContext) {
final long startTime = System.nanoTime();
String propertyKeyPrefix = node.getText().substring(0, caretPosition - start);
propertyKeyPrefix = propertyKeyPrefix.replace(Proposer.PREFIX_MARKER, "");
final StringBuilder newQueryPattern = new StringBuilder(query);
newQueryPattern.replace(start, end + 1, "%s");
addProposalsForKeys(propertyKeyPrefix, newQueryPattern.toString());
METRICS_LOGGER.debug("proposals for property key {} took {} ms", propertyKeyPrefix,
(System.nanoTime() - startTime) / 1_000_000.0);
}
}
}
@Override
public void syntaxError(final Recognizer<?, ?> recognizer, final Object offendingSymbol, final int line,
final int charPositionInLine, final String msg, final RecognitionException e) {
if (!isEOF(offendingSymbol) && offendingSymbol instanceof CommonToken) {
final CommonToken token = (CommonToken) offendingSymbol;
final String text = token.getText();
if ("and".startsWith(text)) {
final StringBuilder newQuery = new StringBuilder(query);
newQuery.replace(charPositionInLine, charPositionInLine + text.length(), " and ");
proposals.add(new Proposal(" and ", newQuery.toString(), true, newQuery.toString(),
charPositionInLine + text.length()));
}
if ("or".startsWith(text)) {
final StringBuilder newQuery = new StringBuilder(query);
newQuery.replace(charPositionInLine, charPositionInLine + text.length(), " or ");
proposals.add(new Proposal(" or ", newQuery.toString(), true, newQuery.toString(),
charPositionInLine + text.length()));
}
}
}
private void addProposalsForKeys(final String propertyKeyPrefix, final String newQueryPattern) {
final List<String> availableKeys = dataStore.getAvailableFields();
final List<String> matchingKeys = CollectionUtils.filter(availableKeys,
s -> s.startsWith(propertyKeyPrefix));
matchingKeys.stream()//
.map(key -> {
final String newQueryWithMarker = String.format(newQueryPattern, key + "=" + CARET_MARKER)
.replaceAll("\\s+", " ");
final int newCaretPosition = newQueryWithMarker.indexOf(CARET_MARKER);
final String newQuery = newQueryWithMarker.replace(CARET_MARKER, "");
return new Proposal(key, String.format(newQueryPattern, key + "=* "), true, newQuery,
newCaretPosition);
}).forEach(proposals::add);
}
private boolean isEOF(final Object offendingSymbol) {
if (offendingSymbol instanceof CommonToken) {
return ((CommonToken) offendingSymbol).getType() < 0;
}
return false;
}
@Override
public void visitErrorNode(final ErrorNode node) {
}
@Override
public void enterEveryRule(final ParserRuleContext ctx) {
}
@Override
public void exitEveryRule(final ParserRuleContext ctx) {
}
@Override
public void enterStart(final StartContext ctx) {
}
@Override
public void exitStart(final StartContext ctx) {
}
@Override
public void enterBinaryOrExpression(final BinaryOrExpressionContext ctx) {
}
@Override
public void exitBinaryOrExpression(final BinaryOrExpressionContext ctx) {
}
@Override
public void enterBinaryAndExpression(final BinaryAndExpressionContext ctx) {
}
@Override
public void exitBinaryAndExpression(final BinaryAndExpressionContext ctx) {
}
@Override
public void enterNotExpression(final NotExpressionContext ctx) {
}
@Override
public void exitNotExpression(final NotExpressionContext ctx) {
}
@Override
public void enterParenExpression(final ParenExpressionContext ctx) {
}
@Override
public void exitParenExpression(final ParenExpressionContext ctx) {
}
@Override
public void enterPropertyExpression(final PropertyExpressionContext ctx) {
}
@Override
public void exitPropertyExpression(final PropertyExpressionContext ctx) {
}
@Override
public void enterIdentifierExpression(final IdentifierExpressionContext ctx) {
}
@Override
public void exitIdentifierExpression(final IdentifierExpressionContext ctx) {
}
@Override
public void enterPropertyTerminalExpression(final PropertyTerminalExpressionContext ctx) {
}
@Override
public void exitPropertyTerminalExpression(final PropertyTerminalExpressionContext ctx) {
}
private SortedSet<String> getPropertyValuesByPrefix(final String propertyKey,
final String propertyValuePrefix) {
final SortedSet<String> availableValuesForKey = dataStore.getAvailableValuesForKey("", propertyKey);
final SortedSet<String> result = filterValues(availableValuesForKey, propertyValuePrefix);
return result;
}
@Override
public void enterEqual(final EqualContext ctx) {
}
@Override
public void exitEqual(final EqualContext ctx) {
}
private boolean isEOF(final TerminalNode node) {
return node.getSymbol().getType() < 0;
}
private boolean containsCaret(final TerminalNode node) {
final int start = node.getSymbol().getStartIndex();
final int end = node.getSymbol().getStopIndex();
return start <= caretPosition && end + 1 >= caretPosition;
}
@Override
public void reportAmbiguity(final Parser recognizer, final DFA dfa, final int startIndex, final int stopIndex,
final boolean exact, final BitSet ambigAlts, final ATNConfigSet configs) {
}
@Override
public void reportAttemptingFullContext(final Parser recognizer, final DFA dfa, final int startIndex,
final int stopIndex, final BitSet conflictingAlts, final ATNConfigSet configs) {
}
@Override
public void reportContextSensitivity(final Parser recognizer, final DFA dfa, final int startIndex,
final int stopIndex, final int prediction, final ATNConfigSet configs) {
}
@Override
public void enterListOfPropValues(final ListOfPropValuesContext ctx) {
}
@Override
public void exitListOfPropValues(final ListOfPropValuesContext ctx) {
}
@Override
public void enterEnclosedListOfPropValues(final EnclosedListOfPropValuesContext ctx) {
}
@Override
public void exitEnclosedListOfPropValues(final EnclosedListOfPropValuesContext ctx) {
}
}
public QueryCompletionPdbLangParser(final TokenStream input) {
super(input);
}
static SortedSet<String> filterValues(final Collection<String> availableValues, final String valuePattern) {
final SortedSet<String> result = new TreeSet<>();
final Pattern pattern = GloblikePattern.globlikeToRegex(valuePattern);
for (final String value : availableValues) {
final Matcher matcher = pattern.matcher(value);
if (matcher.find() && !value.equals(valuePattern)) {
result.add(value);
}
}
return result;
}
}

View File

@@ -1,83 +0,0 @@
package org.lucares.pdb.datastore.lang;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@Test
public class QueryCompletionPdbLangParserTest {
@DataProvider
public Object[][] providerPatterns() {
final List<Object[]> result = new ArrayList<>();
// opinion-size-age-shape-colour-origin-material-purpose Noun
final List<String> availableValues = new ArrayList<>();
availableValues.add("Tim");
availableValues.add("Timothy");
availableValues.add("Tanja");
availableValues.add("Danja");
availableValues.add("Wanja");
availableValues.add("BigOldGrey.Jennifer");
availableValues.add("BigYoungGreen.Jennifer");
availableValues.add("BigYoungBlue.Jenny");
availableValues.add("SmallRoundBlue.Peter");
{
// infix does not match
final SortedSet<String> expected = new TreeSet<>();
result.add(new Object[] { availableValues, "nj", expected });
}
{
final SortedSet<String> expected = new TreeSet<>();
expected.add("Danja");
expected.add("Tanja");
expected.add("Wanja");
result.add(new Object[] { availableValues, "*nj", expected });
}
{
final SortedSet<String> expected = new TreeSet<>();
expected.add("BigYoungBlue.Jenny");
result.add(new Object[] { availableValues, "BYB", expected });
}
{
final SortedSet<String> expected = new TreeSet<>();
expected.add("BigOldGrey.Jennifer");
expected.add("BigYoungGreen.Jennifer");
result.add(new Object[] { availableValues, "B*Gr", expected });
}
{
final SortedSet<String> expected = new TreeSet<>();
expected.add("BigOldGrey.Jennifer");
expected.add("BigYoungGreen.Jennifer");
expected.add("BigYoungBlue.Jenny");
result.add(new Object[] { availableValues, ".Jen", expected });
}
{
final SortedSet<String> expected = new TreeSet<>();
expected.add("BigYoungBlue.Jenny");
expected.add("BigYoungGreen.Jennifer");
result.add(new Object[] { availableValues, "BY.Jen", expected });
}
return result.toArray(new Object[0][]);
}
@Test(dataProvider = "providerPatterns")
public void testPatterns(final List<String> availableValues, final String valuePattern,
final SortedSet<String> expectedValues) {
final SortedSet<String> actual = QueryCompletionPdbLangParser.filterValues(availableValues, valuePattern);
Assert.assertEquals(actual, expectedValues);
}
}