use of org.apache.jackrabbit.oak.plugins.index.search.spi.query.FulltextIndexPlanner.PlanResult in project jackrabbit-oak by apache.
the class LucenePropertyIndex method getLuceneRequest.
/**
* Get the Lucene query for the given filter.
*
* @param plan index plan containing filter details
* @param reader the Lucene reader
* @return the Lucene query
*/
private static LuceneRequestFacade getLuceneRequest(IndexPlan plan, IndexAugmentorFactory augmentorFactory, IndexReader reader) {
FulltextQueryTermsProvider augmentor = getIndexAgumentor(plan, augmentorFactory);
List<Query> qs = new ArrayList<>();
Filter filter = plan.getFilter();
FullTextExpression ft = filter.getFullTextConstraint();
PlanResult planResult = getPlanResult(plan);
LuceneIndexDefinition defn = (LuceneIndexDefinition) planResult.indexDefinition;
Analyzer analyzer = defn.getAnalyzer();
if (ft == null) {
// there might be no full-text constraint
// when using the LowCostLuceneIndexProvider
// which is used for testing
} else {
qs.add(getFullTextQuery(plan, ft, analyzer, augmentor));
}
// Check if native function is supported
PropertyRestriction pr = null;
if (defn.hasFunctionDefined()) {
pr = filter.getPropertyRestriction(defn.getFunctionName());
}
if (pr != null) {
String query = String.valueOf(pr.first.getValue(pr.first.getType()));
QueryParser queryParser = new QueryParser(VERSION, "", analyzer);
if (query.startsWith("mlt?")) {
String mltQueryString = query.replace("mlt?", "");
if (reader != null) {
List<PropertyDefinition> sp = new LinkedList<>();
for (IndexingRule r : defn.getDefinedRules()) {
sp.addAll(r.getSimilarityProperties());
}
if (sp.isEmpty()) {
Query moreLikeThis = MoreLikeThisHelper.getMoreLikeThis(reader, analyzer, mltQueryString);
if (moreLikeThis != null) {
qs.add(moreLikeThis);
}
} else {
Query similarityQuery = SimSearchUtils.getSimilarityQuery(sp, reader, mltQueryString);
if (similarityQuery != null) {
qs.add(similarityQuery);
}
}
}
} else if (query.startsWith("spellcheck?")) {
String spellcheckQueryString = query.replace("spellcheck?", "");
if (reader != null) {
return new LuceneRequestFacade<>(SpellcheckHelper.getSpellcheckQuery(spellcheckQueryString, reader));
}
} else if (query.startsWith("suggest?")) {
String suggestQueryString = query.replace("suggest?", "");
if (reader != null) {
return new LuceneRequestFacade<>(SuggestHelper.getSuggestQuery(suggestQueryString));
}
} else {
try {
qs.add(queryParser.parse(query));
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
} else if (planResult.evaluateNonFullTextConstraints()) {
addNonFullTextConstraints(qs, plan, reader);
}
if (qs.size() == 0 && plan.getSortOrder() != null) {
// This case indicates that query just had order by and no
// property restriction defined. In this case property
// existence queries for each sort entry
List<OrderEntry> orders = removeNativeSort(plan.getSortOrder());
for (int i = 0; i < orders.size(); i++) {
OrderEntry oe = orders.get(i);
PropertyDefinition pd = planResult.getOrderedProperty(i);
PropertyRestriction orderRest = new PropertyRestriction();
orderRest.propertyName = oe.getPropertyName();
Query q = createQuery(oe.getPropertyName(), orderRest, pd);
if (q != null) {
qs.add(q);
}
}
}
if (qs.size() == 0) {
if (reader == null) {
// just return match all queries
return new LuceneRequestFacade<Query>(new MatchAllDocsQuery());
}
// be returned (if the index definition has a single rule)
if (planResult.evaluateNodeTypeRestriction()) {
return new LuceneRequestFacade<Query>(new MatchAllDocsQuery());
}
throw new IllegalStateException("No query created for filter " + filter);
}
return performAdditionalWraps(qs);
}
use of org.apache.jackrabbit.oak.plugins.index.search.spi.query.FulltextIndexPlanner.PlanResult in project jackrabbit-oak by apache.
the class LucenePropertyIndex method mergePropertyIndexResult.
@SuppressWarnings("Guava")
private static Iterator<FulltextResultRow> mergePropertyIndexResult(IndexPlan plan, NodeState rootState, Iterator<FulltextResultRow> itr) {
PlanResult pr = getPlanResult(plan);
HybridPropertyIndexLookup lookup = new HybridPropertyIndexLookup(pr.indexPath, NodeStateUtils.getNode(rootState, pr.indexPath), plan.getPathPrefix(), false);
PropertyIndexResult pir = pr.getPropertyIndexResult();
FluentIterable<String> paths;
if (pir != null) {
Iterable<String> queryResult = lookup.query(plan.getFilter(), pir.propertyName, pir.pr);
paths = FluentIterable.from(queryResult).transform(path -> pr.isPathTransformed() ? pr.transformPath(path) : path).filter(notNull());
} else {
// Either of property or nodetype should not be null
checkState(pr.evaluateSyncNodeTypeRestriction());
Filter filter = plan.getFilter();
paths = FluentIterable.from(Iterables.concat(lookup.query(filter, JCR_PRIMARYTYPE, newName(filter.getPrimaryTypes())), lookup.query(filter, JCR_MIXINTYPES, newName(filter.getMixinTypes()))));
}
// No need for path restriction evaluation as thats taken care by PropertyIndex impl itself
// via content mirror strategy
FluentIterable<FulltextResultRow> propIndex = paths.transform(path -> new FulltextResultRow(path, 0, null, null, null));
// Property index itr should come first
return Iterators.concat(propIndex.iterator(), itr);
}
use of org.apache.jackrabbit.oak.plugins.index.search.spi.query.FulltextIndexPlanner.PlanResult in project jackrabbit-oak by apache.
the class LucenePropertyIndex method getFullTextQuery.
static Query getFullTextQuery(final IndexPlan plan, FullTextExpression ft, final Analyzer analyzer, final FulltextQueryTermsProvider augmentor) {
final PlanResult pr = getPlanResult(plan);
// a reference to the query, so it can be set in the visitor
// (a "non-local return")
final AtomicReference<Query> result = new AtomicReference<>();
ft.accept(new FullTextVisitor() {
@Override
public boolean visit(FullTextContains contains) {
visitTerm(contains.getPropertyName(), contains.getRawText(), null, contains.isNot());
return true;
}
@Override
public boolean visit(FullTextOr or) {
BooleanQuery q = new BooleanQuery();
for (FullTextExpression e : or.list) {
Query x = getFullTextQuery(plan, e, analyzer, augmentor);
q.add(x, SHOULD);
}
result.set(q);
return true;
}
@Override
public boolean visit(FullTextAnd and) {
BooleanQuery q = new BooleanQuery();
for (FullTextExpression e : and.list) {
Query x = getFullTextQuery(plan, e, analyzer, augmentor);
/* Only unwrap the clause if MUST_NOT(x) */
boolean hasMustNot = false;
if (x instanceof BooleanQuery) {
BooleanQuery bq = (BooleanQuery) x;
if ((bq.getClauses().length == 1) && (bq.getClauses()[0].getOccur() == BooleanClause.Occur.MUST_NOT)) {
hasMustNot = true;
q.add(bq.getClauses()[0]);
}
}
if (!hasMustNot) {
q.add(x, MUST);
}
}
result.set(q);
return true;
}
@Override
public boolean visit(FullTextTerm term) {
return visitTerm(term.getPropertyName(), term.getText(), term.getBoost(), term.isNot());
}
private boolean visitTerm(String propertyName, String text, String boost, boolean not) {
String p = getLuceneFieldName(propertyName, pr);
Query q = tokenToQuery(text, p, pr, analyzer, augmentor);
if (q == null) {
return false;
}
if (boost != null) {
q.setBoost(Float.parseFloat(boost));
}
if (not) {
BooleanQuery bq = new BooleanQuery();
bq.add(q, MUST_NOT);
result.set(bq);
} else {
result.set(q);
}
return true;
}
});
return result.get();
}
use of org.apache.jackrabbit.oak.plugins.index.search.spi.query.FulltextIndexPlanner.PlanResult in project jackrabbit-oak by apache.
the class ElasticRequestHandler method nonFullTextConstraints.
private List<Query> nonFullTextConstraints(IndexPlan plan, PlanResult planResult) {
final BiPredicate<Iterable<String>, String> any = (iterable, value) -> StreamSupport.stream(iterable.spliterator(), false).anyMatch(value::equals);
final List<Query> queries = new ArrayList<>();
Filter filter = plan.getFilter();
if (!filter.matchesAllTypes()) {
queries.add(nodeTypeConstraints(planResult.indexingRule, filter));
}
String path = FulltextIndex.getPathRestriction(plan);
switch(filter.getPathRestriction()) {
case ALL_CHILDREN:
if (!"/".equals(path)) {
queries.add(newAncestorQuery(path));
}
break;
case DIRECT_CHILDREN:
queries.add(Query.of(q -> q.bool(b -> b.must(newAncestorQuery(path)).must(newDepthQuery(path, planResult)))));
break;
case EXACT:
// deduced
if (planResult.isPathTransformed()) {
String parentPathSegment = planResult.getParentPathSegment();
if (!any.test(PathUtils.elements(parentPathSegment), "*")) {
queries.add(newPathQuery(path + parentPathSegment));
}
} else {
queries.add(newPathQuery(path));
}
break;
case PARENT:
if (PathUtils.denotesRoot(path)) {
// there's no parent of the root node
// we add a path that can not possibly occur because there
// is no way to say "match no documents" in Lucene
queries.add(newPathQuery("///"));
} else {
// deduced
if (planResult.isPathTransformed()) {
String parentPathSegment = planResult.getParentPathSegment();
if (!any.test(PathUtils.elements(parentPathSegment), "*")) {
queries.add(newPathQuery(PathUtils.getParentPath(path) + parentPathSegment));
}
} else {
queries.add(newPathQuery(PathUtils.getParentPath(path)));
}
}
break;
case NO_RESTRICTION:
break;
}
for (Filter.PropertyRestriction pr : filter.getPropertyRestrictions()) {
String name = pr.propertyName;
if (QueryConstants.REP_EXCERPT.equals(name) || QueryConstants.OAK_SCORE_EXPLANATION.equals(name) || QueryConstants.REP_FACET.equals(name)) {
continue;
}
if (QueryConstants.RESTRICTION_LOCAL_NAME.equals(name)) {
if (planResult.evaluateNodeNameRestriction()) {
queries.add(nodeName(pr));
}
continue;
}
if (IndexConstants.INDEX_TAG_OPTION.equals(name) || IndexConstants.INDEX_NAME_OPTION.equals(name)) {
continue;
}
if (pr.first != null && pr.first.equals(pr.last) && pr.firstIncluding && pr.lastIncluding) {
String first = pr.first.getValue(Type.STRING);
first = first.replace("\\", "");
if (JCR_PATH.equals(name)) {
queries.add(newPathQuery(first));
continue;
} else if ("*".equals(name)) {
// TODO Revisit reference constraint. For performant impl
// references need to be indexed in a different manner
queries.add(referenceConstraint(first));
continue;
}
}
PropertyDefinition pd = planResult.getPropDefn(pr);
if (pd == null) {
continue;
}
queries.add(createQuery(planResult.getPropertyName(pr), pr, pd));
}
return queries;
}
use of org.apache.jackrabbit.oak.plugins.index.search.spi.query.FulltextIndexPlanner.PlanResult in project jackrabbit-oak by apache.
the class ElasticRequestHandler method baseQuery.
public Query baseQuery() {
return Query.of(fn -> {
fn.bool(fnb -> {
FullTextExpression ft = filter.getFullTextConstraint();
if (ft != null) {
fnb.must(fullTextQuery(ft, planResult));
}
if (propertyRestrictionQuery != null) {
if (propertyRestrictionQuery.startsWith("mlt?")) {
List<PropertyDefinition> sp = elasticIndexDefinition.getSimilarityProperties();
String mltQueryString = propertyRestrictionQuery.substring("mlt?".length());
Map<String, String> mltParams = MoreLikeThisHelperUtil.getParamMapFromMltQuery(mltQueryString);
String queryNodePath = mltParams.get(MoreLikeThisHelperUtil.MLT_STREAM_BODY);
if (queryNodePath == null) {
// IT is not supported in our lucene implementation.
throw new IllegalArgumentException("Missing required field stream.body in MLT query: " + mltQueryString);
}
if (sp.isEmpty()) {
// SimilarityImpl in oak-core sets property restriction for sim search and the
// query is something like
// mlt?mlt.fl=:path&mlt.mindf=0&stream.body=<path> . We need parse this query
// string and turn into a query
// elastic can understand.
fnb.must(m -> m.moreLikeThis(mltQuery(mltParams)));
} else {
fnb.must(m -> m.bool(similarityQuery(queryNodePath, sp)));
}
if (elasticIndexDefinition.areSimilarityTagsEnabled()) {
// add should clause to improve relevance using similarity tags
fnb.should(s -> s.moreLikeThis(m -> m.fields(ElasticIndexDefinition.SIMILARITY_TAGS).like(l -> l.document(d -> d.id(ElasticIndexUtils.idFromPath(queryNodePath)))).minTermFreq(1).minDocFreq(1).boost(elasticIndexDefinition.getSimilarityTagsBoost())));
}
} else {
fnb.must(m -> m.queryString(qs -> qs.query(propertyRestrictionQuery)));
}
} else if (planResult.evaluateNonFullTextConstraints()) {
for (Query constraint : nonFullTextConstraints(indexPlan, planResult)) {
fnb.filter(constraint);
}
}
return fnb;
});
return fn;
});
}
Aggregations