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;
}
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;
}
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;
}
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;
}
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);
}
Aggregations