Search in sources :

Example 11 with OrderEntry

use of org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry in project jackrabbit-oak by apache.

the class FulltextIndexPlanner method createSortOrder.

protected List<OrderEntry> createSortOrder(IndexDefinition.IndexingRule rule) {
    if (sortOrder == null) {
        return Collections.emptyList();
    }
    List<OrderEntry> orderEntries = newArrayListWithCapacity(sortOrder.size());
    for (OrderEntry o : sortOrder) {
        PropertyDefinition pd = rule.getConfig(o.getPropertyName());
        if (pd != null && pd.ordered && o.getPropertyType() != null && !o.getPropertyType().isArray()) {
            // can manage any order desc/asc
            orderEntries.add(o);
            result.sortedProperties.add(pd);
        } else if (o.getPropertyName().equals(IndexDefinition.NATIVE_SORT_ORDER.getPropertyName())) {
            // Supports jcr:score descending natively
            orderEntries.add(IndexDefinition.NATIVE_SORT_ORDER);
        }
        for (PropertyDefinition functionIndex : rule.getFunctionRestrictions()) {
            if (functionIndex.ordered && o.getPropertyName().equals(functionIndex.function)) {
                // can manage any order desc/asc
                orderEntries.add(o);
                result.sortedProperties.add(functionIndex);
            }
        }
    }
    // TODO Should we return order entries only when all order clauses are satisfied
    return orderEntries;
}
Also used : OrderEntry(org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry) PropertyDefinition(org.apache.jackrabbit.oak.plugins.index.search.PropertyDefinition)

Example 12 with OrderEntry

use of org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry in project jackrabbit-oak by apache.

the class FulltextIndexPlanner method getPlanBuilder.

private IndexPlan.Builder getPlanBuilder() {
    log.trace("Evaluating plan with index definition {}", definition);
    if (wrongIndex()) {
        return null;
    }
    if (filter.getQueryLimits().getStrictPathRestriction().equals(StrictPathRestriction.ENABLE.name()) && !isPlanWithValidPathFilter()) {
        return null;
    }
    if (!definition.getVersion().isAtLeast(IndexFormatVersion.V2)) {
        log.trace("Index is old format. Not supported");
        return null;
    }
    FullTextExpression ft = filter.getFullTextConstraint();
    // Query Fulltext and Index does not support fulltext
    if (ft != null && !definition.isFullTextEnabled()) {
        return null;
    }
    IndexDefinition.IndexingRule indexingRule = getApplicableRule();
    if (indexingRule == null) {
        return null;
    }
    // Query Fulltext and indexing rule does not support fulltext
    if (ft != null && !indexingRule.isFulltextEnabled()) {
        return null;
    }
    if (!checkForQueryPaths()) {
        log.trace("Opting out due mismatch between path restriction {} and query paths {}", filter.getPath(), definition.getQueryPaths());
        return null;
    }
    result = new PlanResult(indexPath, definition, indexingRule);
    if (definition.hasFunctionDefined() && filter.getPropertyRestriction(definition.getFunctionName()) != null) {
        return getNativeFunctionPlanBuilder(indexingRule.getBaseNodeType());
    }
    List<String> indexedProps = newArrayListWithCapacity(filter.getPropertyRestrictions().size());
    for (PropertyDefinition functionIndex : indexingRule.getFunctionRestrictions()) {
        for (PropertyRestriction pr : filter.getPropertyRestrictions()) {
            String f = functionIndex.function;
            if (pr.propertyName.equals(f)) {
                indexedProps.add(f);
                result.propDefns.put(f, functionIndex);
            }
        }
    }
    // Optimization - Go further only if any of the property is configured
    // for property index
    List<String> facetFields = new LinkedList<String>();
    boolean ntBaseRule = NT_BASE.equals(indexingRule.getNodeTypeName());
    Map<String, PropertyDefinition> relativePropDefns = new HashMap<>();
    if (indexingRule.propertyIndexEnabled) {
        for (PropertyRestriction pr : filter.getPropertyRestrictions()) {
            String name = pr.propertyName;
            if (QueryConstants.RESTRICTION_LOCAL_NAME.equals(name)) {
                continue;
            }
            if (name.startsWith(QueryConstants.FUNCTION_RESTRICTION_PREFIX)) {
                // function-based indexes were handled before
                continue;
            }
            if (QueryConstants.REP_FACET.equals(pr.propertyName)) {
                String value = pr.first.getValue(Type.STRING);
                String facetProp = FulltextIndex.parseFacetField(value);
                PropertyDefinition facetPropDef = indexingRule.getConfig(facetProp);
                if (facetPropDef == null || !facetPropDef.facet) {
                    log.debug("{} not backed by index. Opting out", value);
                    return null;
                }
                facetFields.add(facetProp);
            }
            PropertyDefinition pd = indexingRule.getConfig(pr.propertyName);
            boolean relativeProps = false;
            if (pd == null && ntBaseRule) {
                // Direct match not possible. Check for relative property definition
                // i.e. if no match found for jcr:content/@keyword then check if
                // property definition exists for 'keyword'
                pd = getSimpleProperty(indexingRule, pr.propertyName);
                relativeProps = pd != null;
            }
            if (pd != null && pd.propertyIndexEnabled()) {
                if (pr.isNullRestriction() && !pd.nullCheckEnabled) {
                    continue;
                }
                if (!matchesValuePattern(pr, pd)) {
                    continue;
                }
                // with some other definitions
                if (pd.weight != 0 && !relativeProps) {
                    indexedProps.add(name);
                }
                if (relativeProps) {
                    relativePropDefns.put(name, pd);
                } else {
                    result.propDefns.put(name, pd);
                }
            }
        }
    }
    boolean evalNodeTypeRestrictions = canEvalNodeTypeRestrictions(indexingRule);
    boolean evalPathRestrictions = canEvalPathRestrictions(indexingRule);
    boolean canEvalAlFullText = canEvalAllFullText(indexingRule, ft);
    boolean canEvalNodeNameRestriction = canEvalNodeNameRestriction(indexingRule);
    if (ft != null && !canEvalAlFullText) {
        return null;
    }
    if (indexedProps.isEmpty() && !relativePropDefns.isEmpty() && !canEvalAlFullText) {
        indexedProps = planForRelativeProperties(relativePropDefns);
    }
    // Fulltext expression can also be like jcr:contains(jcr:content/metadata/@format, 'image')
    List<OrderEntry> sortOrder = createSortOrder(indexingRule);
    boolean canSort = canSortByProperty(sortOrder);
    if (!indexedProps.isEmpty() || canSort || ft != null || evalPathRestrictions || evalNodeTypeRestrictions || canEvalNodeNameRestriction) {
        int costPerEntryFactor = 1;
        costPerEntryFactor += sortOrder.size();
        IndexPlan.Builder plan = defaultPlan();
        if (plan == null) {
            return null;
        }
        if (filter.getQueryLimits().getStrictPathRestriction().equals(StrictPathRestriction.WARN.name()) && !isPlanWithValidPathFilter()) {
            plan.setLogWarningForPathFilterMismatch(true);
        }
        Pattern queryFilterPattern = definition.getQueryFilterRegex() != null ? definition.getQueryFilterRegex() : definition.getPropertyRegex();
        if (queryFilterPattern != null) {
            if (ft != null && !queryFilterPattern.matcher(ft.toString()).find()) {
                plan.addAdditionalMessage(Level.WARN, "Potentially improper use of index " + definition.getIndexPath() + " with queryFilterRegex " + queryFilterPattern + " to search for value '" + ft + "'");
            }
            for (PropertyRestriction pr : filter.getPropertyRestrictions()) {
                // Ignore properties beginning with ";" like :indexTag / :indexName etx
                if (!pr.propertyName.startsWith(":") && !queryFilterPattern.matcher(pr.toString()).find()) {
                    plan.addAdditionalMessage(Level.WARN, "Potentially improper use of index " + definition.getIndexPath() + " with queryFilterRegex " + queryFilterPattern + " to search for value '" + pr + "'");
                }
            }
        }
        if (!sortOrder.isEmpty()) {
            plan.setSortOrder(sortOrder);
        }
        if (facetFields.size() > 0) {
            plan.setAttribute(ATTR_FACET_FIELDS, facetFields);
        }
        if (ft == null) {
            result.enableNonFullTextConstraints();
        }
        if (evalNodeTypeRestrictions) {
            result.enableNodeTypeEvaluation();
        }
        if (canEvalNodeNameRestriction) {
            result.enableNodeNameRestriction();
        }
        // Set a index based guess here. Unique would set its own value below
        if (useActualEntryCount && !definition.isEntryCountDefined()) {
            int maxPossibleNumDocs = getMaxPossibleNumDocs(result.propDefns, filter);
            if (maxPossibleNumDocs >= 0) {
                plan.setEstimatedEntryCount(maxPossibleNumDocs);
            }
        }
        if (sortOrder.isEmpty() && ft == null) {
            boolean uniqueIndexFound = planForSyncIndexes(indexingRule);
            if (uniqueIndexFound) {
                // For unique index there would be at max 1 entry
                plan.setEstimatedEntryCount(1);
            }
        }
        return plan.setCostPerEntry(definition.getCostPerEntry() / costPerEntryFactor);
    }
    return null;
}
Also used : PropertyRestriction(org.apache.jackrabbit.oak.spi.query.Filter.PropertyRestriction) Pattern(java.util.regex.Pattern) Maps.newHashMap(com.google.common.collect.Maps.newHashMap) HashMap(java.util.HashMap) IndexingRule(org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition.IndexingRule) PropertyDefinition(org.apache.jackrabbit.oak.plugins.index.search.PropertyDefinition) LinkedList(java.util.LinkedList) OrderEntry(org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry) IndexDefinition(org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition) IndexPlan(org.apache.jackrabbit.oak.spi.query.QueryIndex.IndexPlan) FullTextExpression(org.apache.jackrabbit.oak.spi.query.fulltext.FullTextExpression)

Example 13 with OrderEntry

use of org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry in project jackrabbit-oak by apache.

the class IndexPlanner method createSortOrder.

private List<OrderEntry> createSortOrder(IndexingRule rule) {
    if (sortOrder == null) {
        return Collections.emptyList();
    }
    List<OrderEntry> orderEntries = newArrayListWithCapacity(sortOrder.size());
    for (OrderEntry o : sortOrder) {
        PropertyDefinition pd = rule.getConfig(o.getPropertyName());
        if (pd != null && pd.ordered && o.getPropertyType() != null && !o.getPropertyType().isArray()) {
            // Lucene can manage any order desc/asc
            orderEntries.add(o);
            result.sortedProperties.add(pd);
        } else if (o.getPropertyName().equals(IndexDefinition.NATIVE_SORT_ORDER.getPropertyName())) {
            // Supports jcr:score descending natively
            orderEntries.add(IndexDefinition.NATIVE_SORT_ORDER);
        }
        for (PropertyDefinition functionIndex : rule.getFunctionRestrictions()) {
            if (o.getPropertyName().equals(functionIndex.function)) {
                // Lucene can manage any order desc/asc
                orderEntries.add(o);
                result.sortedProperties.add(functionIndex);
            }
        }
    }
    // TODO Should we return order entries only when all order clauses are satisfied
    return orderEntries;
}
Also used : OrderEntry(org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry)

Example 14 with OrderEntry

use of org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry in project jackrabbit-oak by apache.

the class QueryImpl method getSortOrder.

private List<OrderEntry> getSortOrder(FilterImpl filter) {
    if (orderings == null) {
        return null;
    }
    ArrayList<OrderEntry> sortOrder = new ArrayList<OrderEntry>();
    for (OrderingImpl o : orderings) {
        DynamicOperandImpl op = o.getOperand();
        OrderEntry e = op.getOrderEntry(filter.getSelector(), o);
        if (e == null) {
            continue;
        }
        sortOrder.add(e);
    }
    if (sortOrder.size() == 0) {
        return null;
    }
    return sortOrder;
}
Also used : DynamicOperandImpl(org.apache.jackrabbit.oak.query.ast.DynamicOperandImpl) OrderEntry(org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry) OrderingImpl(org.apache.jackrabbit.oak.query.ast.OrderingImpl) Lists.newArrayList(com.google.common.collect.Lists.newArrayList) ArrayList(java.util.ArrayList)

Example 15 with OrderEntry

use of org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry in project jackrabbit-oak by apache.

the class IndexPlannerTest method syncIndex_NotUsedWithFulltext.

@Test
public void syncIndex_NotUsedWithFulltext() throws Exception {
    LuceneIndexDefinitionBuilder defnb = new LuceneIndexDefinitionBuilder();
    defnb.indexRule("nt:base").property("foo").propertyIndex().sync();
    defnb.indexRule("nt:base").property("bar").analyzed();
    LuceneIndexDefinition defn = new LuceneIndexDefinition(root, defnb.build(), "/foo");
    LuceneIndexNode node = createIndexNode(defn, 100);
    FilterImpl filter = createFilter("nt:base");
    filter.restrictProperty("foo", Operator.EQUAL, PropertyValues.newString("bar"));
    filter.setFullTextConstraint(FullTextParser.parse("bar", "mountain"));
    FulltextIndexPlanner planner = new FulltextIndexPlanner(node, "/foo", filter, ImmutableList.of(new OrderEntry("bar", Type.LONG, OrderEntry.Order.ASCENDING)));
    QueryIndex.IndexPlan plan = planner.getPlan();
    assertNotNull(plan);
    assertEquals(documentsPerValue(100), plan.getEstimatedEntryCount());
    PropertyIndexResult hr = pr(plan).getPropertyIndexResult();
    assertNull(hr);
}
Also used : OrderEntry(org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry) FilterImpl(org.apache.jackrabbit.oak.query.index.FilterImpl) PropertyIndexResult(org.apache.jackrabbit.oak.plugins.index.search.spi.query.FulltextIndexPlanner.PropertyIndexResult) FulltextIndexPlanner(org.apache.jackrabbit.oak.plugins.index.search.spi.query.FulltextIndexPlanner) QueryIndex(org.apache.jackrabbit.oak.spi.query.QueryIndex) LuceneIndexDefinitionBuilder(org.apache.jackrabbit.oak.plugins.index.lucene.util.LuceneIndexDefinitionBuilder) LuceneIndexHelper.newLuceneIndexDefinition(org.apache.jackrabbit.oak.plugins.index.lucene.util.LuceneIndexHelper.newLuceneIndexDefinition) Test(org.junit.Test)

Aggregations

OrderEntry (org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry)19 LuceneIndexHelper.newLuceneIndexDefinition (org.apache.jackrabbit.oak.plugins.index.lucene.util.LuceneIndexHelper.newLuceneIndexDefinition)12 FulltextIndexPlanner (org.apache.jackrabbit.oak.plugins.index.search.spi.query.FulltextIndexPlanner)12 Test (org.junit.Test)12 FilterImpl (org.apache.jackrabbit.oak.query.index.FilterImpl)8 LuceneIndexDefinitionBuilder (org.apache.jackrabbit.oak.plugins.index.lucene.util.LuceneIndexDefinitionBuilder)6 QueryIndex (org.apache.jackrabbit.oak.spi.query.QueryIndex)6 NodeBuilder (org.apache.jackrabbit.oak.spi.state.NodeBuilder)6 IndexPlan (org.apache.jackrabbit.oak.spi.query.QueryIndex.IndexPlan)4 Maps.newHashMap (com.google.common.collect.Maps.newHashMap)2 HashMap (java.util.HashMap)2 LinkedList (java.util.LinkedList)2 PropertyDefinition (org.apache.jackrabbit.oak.plugins.index.search.PropertyDefinition)2 PropertyIndexResult (org.apache.jackrabbit.oak.plugins.index.search.spi.query.FulltextIndexPlanner.PropertyIndexResult)2 DynamicOperandImpl (org.apache.jackrabbit.oak.query.ast.DynamicOperandImpl)2 OrderingImpl (org.apache.jackrabbit.oak.query.ast.OrderingImpl)2 PropertyRestriction (org.apache.jackrabbit.oak.spi.query.Filter.PropertyRestriction)2 FullTextExpression (org.apache.jackrabbit.oak.spi.query.fulltext.FullTextExpression)2 Lists.newArrayList (com.google.common.collect.Lists.newArrayList)1 ArrayList (java.util.ArrayList)1