use of org.apache.jackrabbit.oak.spi.query.fulltext.FullTextExpression in project jackrabbit-oak by apache.
the class IndexPlanner method getPlanBuilder.
private IndexPlan.Builder getPlanBuilder() {
log.trace("Evaluating plan with index definition {}", definition);
if (wrongIndex()) {
return null;
}
FullTextExpression ft = filter.getFullTextConstraint();
if (!definition.getVersion().isAtLeast(IndexFormatVersion.V2)) {
log.trace("Index is old format. Not supported");
return null;
}
// Query Fulltext and Index does not support fulltext
if (ft != null && !definition.isFullTextEnabled()) {
return null;
}
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);
facetFields.add(FacetHelper.parseFacetField(value));
}
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 (!sortOrder.isEmpty()) {
plan.setSortOrder(sortOrder);
}
if (facetFields.size() > 0) {
plan.setAttribute(FacetHelper.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.fulltext.FullTextExpression in project jackrabbit-oak by apache.
the class LuceneIndex method getPlans.
@Override
public List<IndexPlan> getPlans(Filter filter, List<OrderEntry> sortOrder, NodeState rootState) {
FullTextExpression ft = filter.getFullTextConstraint();
if (ft == null) {
// as there might be a better one
return Collections.emptyList();
}
String indexPath = new LuceneIndexLookup(rootState).getOldFullTextIndexPath(filter, tracker);
if (indexPath == null) {
// unusable index
return Collections.emptyList();
}
Set<String> relPaths = getRelativePaths(ft);
if (relPaths.size() > 1) {
LOG.warn("More than one relative parent for query " + filter.getQueryStatement());
// "contains(a/x, 'hello') and contains(b/x, 'world')"
return Collections.emptyList();
}
IndexNode node = tracker.acquireIndexNode(indexPath);
try {
if (node != null) {
IndexDefinition defn = node.getDefinition();
return Collections.singletonList(planBuilder(filter).setEstimatedEntryCount(defn.getFulltextEntryCount(node.getIndexStatistics().numDocs())).setCostPerExecution(defn.getCostPerExecution()).setCostPerEntry(defn.getCostPerEntry()).setAttribute(ATTR_INDEX_PATH, indexPath).build());
}
// No index node then no plan possible
return Collections.emptyList();
} finally {
if (node != null) {
node.release();
}
}
}
use of org.apache.jackrabbit.oak.spi.query.fulltext.FullTextExpression in project jackrabbit-oak by apache.
the class LMSEstimatorTest method testMultipleUpdates.
@Test
public void testMultipleUpdates() throws Exception {
LMSEstimator lmsEstimator = new LMSEstimator();
Filter filter = mock(Filter.class);
FullTextExpression fte = new FullTextTerm("foo", "bar", false, false, "");
when(filter.getFullTextConstraint()).thenReturn(fte);
SolrDocumentList docs = new SolrDocumentList();
lmsEstimator.update(filter, docs);
long actualCount = 10;
docs.setNumFound(actualCount);
long estimate = lmsEstimator.estimate(filter);
assertEquals(estimate, lmsEstimator.estimate(filter));
long diff = actualCount - estimate;
// update causes weights adjustment
lmsEstimator.update(filter, docs);
long estimate2 = lmsEstimator.estimate(filter);
assertEquals(estimate2, lmsEstimator.estimate(filter));
long diff2 = actualCount - estimate2;
// new estimate is more accurate than previous one
assertTrue(diff2 < diff);
// update doesn't cause weight adjustments therefore estimates stays unchanged
lmsEstimator.update(filter, docs);
long estimate3 = lmsEstimator.estimate(filter);
assertEquals(estimate3, lmsEstimator.estimate(filter));
long diff3 = actualCount - estimate3;
assertTrue(diff3 < diff2);
}
use of org.apache.jackrabbit.oak.spi.query.fulltext.FullTextExpression in project jackrabbit-oak by apache.
the class IndexPlannerTest method fullTextQuery_RelativePropertyPaths.
@Test
public void fullTextQuery_RelativePropertyPaths() throws Exception {
NodeBuilder defn = newLucenePropertyIndexDefinition(builder, "test", of("foo", "bar"), "async");
// Index all props and then perform fulltext
defn = IndexDefinition.updateDefinition(defn.getNodeState().builder());
NodeBuilder foob = getNode(defn, "indexRules/nt:base/properties/foo");
foob.setProperty(LuceneIndexConstants.PROP_NAME, "foo");
foob.setProperty(LuceneIndexConstants.PROP_ANALYZED, true);
NodeBuilder barb = getNode(defn, "indexRules/nt:base/properties/bar");
barb.setProperty(LuceneIndexConstants.PROP_NAME, "bar");
barb.setProperty(LuceneIndexConstants.PROP_ANALYZED, true);
// where contains('jcr:content/bar', 'mountain OR valley') and contains('jcr:content/foo', 'mountain OR valley')
// above query can be evaluated by index which indexes foo and bar with restriction that both belong to same node
// by displacing the query path to evaluate on contains('bar', ...) and filter out those parents which do not
// have jcr:content as parent
FullTextExpression fooExp = FullTextParser.parse("jcr:content/bar", "mountain OR valley");
FullTextExpression barExp = FullTextParser.parse("jcr:content/foo", "mountain OR valley");
FullTextExpression exp = new FullTextAnd(Arrays.asList(fooExp, barExp));
IndexPlanner planner = createPlannerForFulltext(defn.getNodeState(), exp);
// No plan for unindex property
assertNotNull(planner.getPlan());
}
use of org.apache.jackrabbit.oak.spi.query.fulltext.FullTextExpression in project jackrabbit-oak by apache.
the class IndexPlannerTest method fullTextQuery_IndexAllProps.
@Test
public void fullTextQuery_IndexAllProps() throws Exception {
NodeBuilder defn = newLucenePropertyIndexDefinition(builder, "test", of("allProps"), "async");
// Index all props and then perform fulltext
defn = IndexDefinition.updateDefinition(defn.getNodeState().builder());
NodeBuilder foob = getNode(defn, "indexRules/nt:base/properties/allProps");
foob.setProperty(LuceneIndexConstants.PROP_NAME, LuceneIndexConstants.REGEX_ALL_PROPS);
foob.setProperty(LuceneIndexConstants.PROP_ANALYZED, true);
foob.setProperty(LuceneIndexConstants.PROP_IS_REGEX, true);
FullTextExpression exp = FullTextParser.parse("bar", "mountain OR valley");
exp = new FullTextContains("bar", "mountain OR valley", exp);
IndexPlanner planner = createPlannerForFulltext(defn.getNodeState(), exp);
// No plan for unindex property
assertNotNull(planner.getPlan());
}
Aggregations