protected static void addSyncIndexPlan(IndexPlan plan, StringBuilder sb) { FulltextIndexPlanner.PlanResult pr = getPlanResult(plan); if (pr.hasPropertyIndexResult()) { FulltextIndexPlanner.PropertyIndexResult pres = pr.getPropertyIndexResult(); sb.append(" sync:(") .append(pres.propertyName); if (!pres.propertyName.equals(pres.pr.propertyName)) { sb.append("[").append(pres.pr.propertyName).append("]"); } sb.append(" ").append(pres.pr); sb.append(")"); } if (pr.evaluateSyncNodeTypeRestriction()) { sb.append(" sync:(nodeType"); sb.append(" primaryTypes : ").append(plan.getFilter().getPrimaryTypes()); sb.append(" mixinTypes : ").append(plan.getFilter().getMixinTypes()); sb.append(")"); } }
@Override public String next() { currentRow = it.next(); readCount++; if (readCount % TRAVERSING_WARNING == 0) { Cursors.checkReadLimit(readCount, settings); log.warn("Index-Traversed {} nodes with filter {}", readCount, plan.getFilter()); } return currentRow.path; }
@Override public String getPlanDescription(IndexPlan plan, NodeState root) { Filter filter = plan.getFilter(); IndexNode index = acquireIndexNode(plan); checkState(index != null, "The fulltext index of type " + getType() + " index is not available"); try { FullTextExpression ft = filter.getFullTextConstraint(); StringBuilder sb = new StringBuilder(getType()).append(":"); String path = getPlanResult(plan).indexPath; sb.append(getIndexName(plan)) .append("(") .append(path) .append(") "); sb.append(getFulltextRequestString(plan, index)); if (plan.getSortOrder() != null && !plan.getSortOrder().isEmpty()) { sb.append(" ordering:").append(plan.getSortOrder()); } if (ft != null) { sb.append(" ft:(").append(ft).append(")"); } addSyncIndexPlan(plan, sb); return sb.toString(); } finally { index.release(); } }
@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 = null; 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 { checkState(pr.evaluateSyncNodeTypeRestriction()); //Either of property or nodetype should not be null 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); }
@Override public String getPlanDescription(IndexPlan plan, NodeState root) { Filter filter = plan.getFilter(); LuceneIndexNode index = tracker.acquireIndexNode((String) plan.getAttribute(ATTR_INDEX_PATH)); checkState(index != null, "The Lucene index is not available"); try { FullTextExpression ft = filter.getFullTextConstraint(); Set<String> relPaths = getRelativePaths(ft); if (relPaths.size() > 1) { return new MultiLuceneIndex(filter, root, relPaths).getPlan(); } String parent = relPaths.size() == 0 ? "" : relPaths.iterator().next(); // we only restrict non-full-text conditions if there is // no relative property in the full-text constraint boolean nonFullTextConstraints = parent.isEmpty(); String planDesc = getLuceneRequest(filter, null, nonFullTextConstraints, index.getDefinition()) + " ft:(" + ft + ")"; if (!parent.isEmpty()) { planDesc += " parent:" + parent; } return planDesc; } finally { index.release(); } }
@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 = null; 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 { checkState(pr.evaluateSyncNodeTypeRestriction()); //Either of property or nodetype should not be null 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); }
@Override public long getSize(SizePrecision precision, long max) { long estimate = -1; switch (precision) { case EXACT: // query solr SolrQuery countQuery = FilterQueryParser.getQuery(plan.getFilter(), plan, this.configuration); countQuery.setRows(0); try { estimate = this.solrServer.query(countQuery).getResults().getNumFound(); } catch (IOException | SolrServerException e) { log.warn("could not perform count query {}", countQuery); } break; case APPROXIMATION: // estimate result size estimate = this.estimator.estimate(plan.getFilter()); break; case FAST_APPROXIMATION: // use already computed index plan's estimate estimate = plan.getEstimatedEntryCount(); break; } return Math.min(estimate, max); } }
@Override public long getSize(SizePrecision precision, long max) { long estimate = -1; switch (precision) { case EXACT: // query solr SolrQuery countQuery = FilterQueryParser.getQuery(plan.getFilter(), plan, this.configuration); countQuery.setRows(0); try { estimate = this.solrServer.query(countQuery).getResults().getNumFound(); } catch (IOException | SolrServerException e) { log.warn("could not perform count query {}", countQuery); } break; case APPROXIMATION: // estimate result size estimate = this.estimator.estimate(plan.getFilter()); break; case FAST_APPROXIMATION: // use already computed index plan's estimate estimate = plan.getEstimatedEntryCount(); break; } return Math.min(estimate, max); } }
@Override public String getPlanDescription(IndexPlan plan, NodeState root) { Filter filter = plan.getFilter(); LuceneIndexNode index = tracker.acquireIndexNode((String) plan.getAttribute(ATTR_INDEX_PATH)); checkState(index != null, "The Lucene index is not available"); try { FullTextExpression ft = filter.getFullTextConstraint(); Set<String> relPaths = getRelativePaths(ft); if (relPaths.size() > 1) { return new MultiLuceneIndex(filter, root, relPaths).getPlan(); } String parent = relPaths.size() == 0 ? "" : relPaths.iterator().next(); // we only restrict non-full-text conditions if there is // no relative property in the full-text constraint boolean nonFullTextConstraints = parent.isEmpty(); String planDesc = getLuceneRequest(filter, null, nonFullTextConstraints, index.getDefinition()) + " ft:(" + ft + ")"; if (!parent.isEmpty()) { planDesc += " parent:" + parent; } return planDesc; } finally { index.release(); } }
@Override public Cursor query(final IndexPlan plan, final NodeState root) { Cursor cursor; try { Filter filter = plan.getFilter(); final Set<String> relPaths = filter.getFullTextConstraint() != null ? getRelativePaths(filter.getFullTextConstraint()) : Collections.<String>emptySet(); final String parent = relPaths.size() == 0 ? "" : relPaths.iterator().next(); final int parentDepth = getDepth(parent); String path = plan.getPlanName(); OakSolrConfiguration configuration = getConfiguration(path, root); SolrClient solrServer = getServer(path, root); LMSEstimator estimator = getEstimator(path); AbstractIterator<SolrResultRow> iterator = getIterator(filter, plan, parent, parentDepth, configuration, solrServer, estimator); cursor = new SolrRowCursor(iterator, plan, filter.getQueryLimits(), estimator, solrServer, configuration); } catch (Exception e) { throw new RuntimeException(e); } return cursor; }
@Override public Cursor query(final IndexPlan plan, final NodeState root) { Cursor cursor; try { Filter filter = plan.getFilter(); final Set<String> relPaths = filter.getFullTextConstraint() != null ? getRelativePaths(filter.getFullTextConstraint()) : Collections.<String>emptySet(); final String parent = relPaths.size() == 0 ? "" : relPaths.iterator().next(); final int parentDepth = getDepth(parent); String path = plan.getPlanName(); OakSolrConfiguration configuration = getConfiguration(path, root); SolrClient solrServer = getServer(path, root); LMSEstimator estimator = getEstimator(path); AbstractIterator<SolrResultRow> iterator = getIterator(filter, plan, parent, parentDepth, configuration, solrServer, estimator); cursor = new SolrRowCursor(iterator, plan, filter.getQueryLimits(), estimator, solrServer, configuration); } catch (Exception e) { throw new RuntimeException(e); } return cursor; }
private static Query addDescendantClauseIfRequired(Query query, IndexPlan plan) { Filter filter = plan.getFilter(); if (filter.getPathRestriction() == Filter.PathRestriction.ALL_CHILDREN) { String path = getPathRestriction(plan); if (!PathUtils.denotesRoot(path)) { if (getPlanResult(plan).indexDefinition.evaluatePathRestrictions()) { BooleanQuery compositeQuery = new BooleanQuery(); compositeQuery.add(query, BooleanClause.Occur.MUST); Query pathQuery = new TermQuery(newAncestorTerm(path)); compositeQuery.add(pathQuery, BooleanClause.Occur.MUST); query = compositeQuery; } else { LOG.warn("Descendant clause could not be added without path restrictions enabled. Plan: {}", plan); } } } return query; }
private static Query addDescendantClauseIfRequired(Query query, IndexPlan plan) { Filter filter = plan.getFilter(); if (filter.getPathRestriction() == Filter.PathRestriction.ALL_CHILDREN) { String path = getPathRestriction(plan); if (!PathUtils.denotesRoot(path)) { if (getPlanResult(plan).indexDefinition.evaluatePathRestrictions()) { BooleanQuery compositeQuery = new BooleanQuery(); compositeQuery.add(query, BooleanClause.Occur.MUST); Query pathQuery = new TermQuery(newAncestorTerm(path)); compositeQuery.add(pathQuery, BooleanClause.Occur.MUST); query = compositeQuery; } else { LOG.warn("Descendant clause could not be added without path restrictions enabled. Plan: {}", plan); } } } return query; }
protected static boolean shouldInclude(String docPath, IndexPlan plan) { String path = getPathRestriction(plan); boolean include = true; Filter filter = plan.getFilter(); switch (filter.getPathRestriction()) { case EXACT: include = path.equals(docPath); break; case DIRECT_CHILDREN: include = PathUtils.getParentPath(docPath).equals(path); break; case ALL_CHILDREN: include = PathUtils.isAncestor(path, docPath); break; } return include; }
@Override public Cursor query(IndexPlan plan, NodeState rootState) { if (getNodeAggregator() == null) { // path-though return baseIndex.query(plan, rootState); } else if (!(plan instanceof AggregateIndexPlan)) { // remove the node type restriction plan.setFilter(newAggregationFilter(plan.getFilter(), null)); return newAggregationCursor(plan, rootState); } Filter filter = plan.getFilter(); AggregateIndexPlan aggPlan = (AggregateIndexPlan) plan; FullTextExpression constraint = filter.getFullTextConstraint(); return flatten(constraint, aggPlan, filter, rootState, ""); }
@Override public Cursor query(IndexPlan plan, NodeState rootState) { if (getNodeAggregator() == null) { // path-though return baseIndex.query(plan, rootState); } else if (!(plan instanceof AggregateIndexPlan)) { // remove the node type restriction plan.setFilter(newAggregationFilter(plan.getFilter(), null)); return newAggregationCursor(plan, rootState); } Filter filter = plan.getFilter(); AggregateIndexPlan aggPlan = (AggregateIndexPlan) plan; FullTextExpression constraint = filter.getFullTextConstraint(); return flatten(constraint, aggPlan, filter, rootState, ""); }
@Override public Cursor query(IndexPlan plan, NodeState rootState) { if (getNodeAggregator() == null) { // path-though return baseIndex.query(plan, rootState); } else if (!(plan instanceof AggregateIndexPlan)) { // remove the node type restriction plan.setFilter(newAggregationFilter(plan.getFilter(), null)); return newAggregationCursor(plan, rootState); } Filter filter = plan.getFilter(); AggregateIndexPlan aggPlan = (AggregateIndexPlan) plan; FullTextExpression constraint = filter.getFullTextConstraint(); return flatten(constraint, aggPlan, filter, rootState, ""); }
@Test public void copy() throws Exception{ Filter f = new FilterImpl(null, "SELECT * FROM [nt:file]", new QueryEngineSettings()); IndexPlan.Builder b = new IndexPlan.Builder(); IndexPlan plan1 = b.setEstimatedEntryCount(10).setFilter(f).setDelayed(true).build(); IndexPlan plan2 = plan1.copy(); plan2.setFilter(new FilterImpl(null, "SELECT * FROM [oak:Unstructured]", new QueryEngineSettings())); assertEquals(plan1.getEstimatedEntryCount(), 10); assertEquals(plan2.getEstimatedEntryCount(), 10); assertTrue(plan1.isDelayed()); assertTrue(plan2.isDelayed()); assertEquals(plan1.getFilter().getQueryStatement(), "SELECT * FROM [nt:file]"); assertEquals(plan2.getFilter().getQueryStatement(), "SELECT * FROM [oak:Unstructured]"); }
protected static String getPathRestriction(IndexPlan plan) { Filter f = plan.getFilter(); String pathPrefix = plan.getPathPrefix(); if (pathPrefix.isEmpty()) { return f.getPath(); } String relativePath = PathUtils.relativize(pathPrefix, f.getPath()); return "/" + relativePath; }