com.day.cq.search.eval.PredicateEvaluator Maven / Gradle / Ivy
Show all versions of aem-sdk-api Show documentation
/*
* Copyright 1997-2008 Day Management AG
* Barfuesserplatz 6, 4001 Basel, Switzerland
* All Rights Reserved.
*
* This software is the confidential and proprietary information of
* Day Management AG, ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Day.
*/
package com.day.cq.search.eval;
import java.util.Comparator;
import javax.jcr.query.Row;
import com.day.cq.search.Predicate;
import com.day.cq.search.PredicateConverter;
import com.day.cq.search.Query;
import com.day.cq.search.facets.Facet;
import com.day.cq.search.facets.FacetExtractor;
import com.day.cq.search.facets.extractors.DistinctValuesFacetExtractor;
import com.day.cq.search.result.SearchResult;
import aQute.bnd.annotation.ConsumerType;
/**
* A PredicateEvaluator
handles the evaluation of certain
* {@link Predicate Predicates}, which are the defining constraints of a
* {@link Query}. Each evaluator handles a certain type of {@link Predicate
* Predicates}, which is given by {@link Predicate#getType()}. Generally
* speaking, it maps a higher-level search constraint, such as "width > 200", to
* a specific JCR query that fits the actual content model, eg.
* metadata/@width > 200
, or it can manually filter nodes and look
* at them to check its constraint.
*
*
* Xpath vs. Filtering: XPath is the query language of choice here, and
* the XPath predicate expression must be returned in
* {@link #getXPathExpression(Predicate, EvaluationContext)}. If the constraint
* of this evaluator cannot be formulated via a JCR XPath predicate expression,
* the result can also be filtered using the
* {@link #includes(Predicate, Row, EvaluationContext)} method. Please note that
* filtering is more likely to negatively impact performance, so xpath is the
* preferred way.
*
*
* Important Note: It is recommended that evaluators implement their
* concept via xpath and filtering (ie. two different implementations
* of the same constraint), or via filtering only. This is because in the case
* of predicate groups that are combined with OR, and at least one of the
* predicates is done only via filtering, the whole group must be done via
* filtering. Filtering itself cannot add new nodes to the result, so the whole
* group must not produce any xpath constraint that would reduce the set
* "too much" before filtering. Not complying to this recommendation will make
* xpath-only predicates not work inside mixed or groups, but can still work for
* other scenarios.
*
*
* Ordering: To sort the result set, an evaluator can either specify one
* or more JCR properties via
* {@link #getOrderByProperties(Predicate, EvaluationContext)} or provide a
* custom comparator that works on the final result set via
* {@link #getOrderByComparator(Predicate, EvaluationContext)}.
*
*
* Facets: A {@link PredicateEvaluator} also provides a
* {@link FacetExtractor} that creates buckets based on the search result, since
* facets will conceptually always match to the types of constraints you can put
* in a query. The {@link #getFacetExtractor(Predicate, EvaluationContext)}
* method returns the extractor that will afterwards run over the result set to
* find any facets.
*
*
* Registration: Implementations of this interface must either be defined
* as OSGi components (to be used for any query) or registered explicitly for a
* certain query using
* {@link Query#registerPredicateEvaluator(String, PredicateEvaluator)}. If the
* OSGi component way is chosen, the component must be defined as a component
* factory. Names should not start with a "_", as they will be ignored for
* queries created from requests (see
* {@link PredicateConverter#createPredicates(java.util.Map)}. The name of the
* factory must be the fully qualified name of this interface plus "/" and the
* type of the predicate this evaluator will be used for. For example for a
* {@link PredicateEvaluator} handling the predicate type "fulltext", the SCR
* annotation would look like this:
*
*
* {@literal @}Component(metatype = false, factory="com.day.cq.search.eval.PredicateEvaluator/fulltext")
*
*
* @since 5.2
*/
@ConsumerType
public interface PredicateEvaluator {
/**
* Returns an XPath predicate expression, which is just a partial
* expression that can be placed inside "[" and "]" in a full XPath
* statement. Examples are:
*
*
* @jcr:title = 'Foobar'
*
*
* or this longer expression:
*
*
* (@count > 10 and @count < 20) or @state = 'foo'
*
*
*
* As a different constraint, an implementation can also filter the result
* of the query, using the
* {@link #includes(Predicate, Row, EvaluationContext)} method. Also, it is
* recommended to implement the xpath-based constraint again inside
* {@linkplain #includes(Predicate, Row, EvaluationContext) includes()} to
* support the case where filtering is forced by a parent predicte group.
*
*
* Note that an implementation must return an empty string or
* null
if its parameters are empty, ie. if the predicate
* should not "take part" in the actual query. This is because we need to
* keep track of the potential predicates for the query to get all
* {@link Facet Facets}, not only the ones for what is already queried.
*
*
* If you implement this method, don't forget to implement
* {@link #canXpath(Predicate, EvaluationContext)} so that it returns true.
*
* @param predicate
* predicate (for this evaluator type) which is evaluated
* @param context
* helper class which provides access to various elements of the
* query evaluation
* @return string containing an XPath predicateEvaluator expression
*/
String getXPathExpression(Predicate predicate, EvaluationContext context);
/**
* If the constraint for the given predicate formulated via a JCR XPath
* expression, this method can be used to filter the result set row by row
* (to get the node behind the row, one can use
* {@link EvaluationContext#getNode(Row) context.getNode(row)}.
*
*
* Please note that this is more likely to negatively impact
* performance!
*
*
* If you implement this method, don't forget to implement
* {@link #canFilter(Predicate, EvaluationContext)} so that it returns true.
*
* @param predicate
* predicate (for this evaluator type) which is evaluated
* @param row
* current row of the result set returned through the xpath query
* @param context
* helper class which provides access to various elements of the
* query evaluation
* @return true
if this row should be part of the final result
* set, false
if it should be dropped
*/
boolean includes(Predicate predicate, Row row, EvaluationContext context);
/**
* Returns whether this evaluator can return its constraint via xpath, ie.
* {@link #getXPathExpression(Predicate, EvaluationContext)}.
*
*
* Note that the result typically does not depend on either the predicate
* or the context (given as parameters) - in most cases this depends
* directly on the implementation.
*
* @param predicate
* predicate (for this evaluator type) which is evaluated
* @param context
* helper class which provides access to various elements of the
* query evaluation
* @return true
if this evaluator can express itself via xpath,
* ie. {@link #getXPathExpression(Predicate, EvaluationContext)}
*
* @since 5.3
*/
boolean canXpath(Predicate predicate, EvaluationContext context);
/**
* Returns whether this evaluator can handle its constraint via filtering,
* ie. {@link #includes(Predicate, Row, EvaluationContext)}.
*
*
* Note that the result typically does not depend on either the predicate
* or the context (given as parameters) - in most cases this depends
* directly on the implementation.
*
* @param predicate
* predicate (for this evaluator type) which is evaluated
* @param context
* helper class which provides access to various elements of the
* query evaluation
* @return true
if this evaluator can be express itself via
* filtering, ie.
* {@link #includes(Predicate, Row, EvaluationContext)}
*
* @since 5.3
*/
boolean canFilter(Predicate predicate, EvaluationContext context);
/**
* Returns true
if the evaluator will actually handle the
* predicate in some way in the
* {@link #includes(Predicate, Row, EvaluationContext)} method. This is
* required to separate evaluators that always return true
in
* {@link #includes(Predicate, Row, EvaluationContext)}, because they don't
* do any filtering, from those that filter the result set and also return
* true
.
*
*
* Note that this should return false
if the predicate is
* "empty", eg. is not providing any required parameters.
*
* @param predicate
* predicate (for this evaluator type) which is evaluated
* @param context
* helper class which provides access to various elements of the
* query evaluation
* @return true
if this evaluator is filtering the result set
* for the given predicate
*
* @deprecated Since 5.3, use
* {@link #canFilter(Predicate, EvaluationContext)} and
* {@link #canXpath(Predicate, EvaluationContext)} instead.
*/
boolean isFiltering(Predicate predicate, EvaluationContext context);
/**
* Returns a list of JCR property names or relative paths
* to properties that should be used when the result should be ordered by
* the given predicate. The paths will be used in the order by
* part of the Xpath query (in the given order). Can return
* null
if there is no property to order by. Additional
* ordering can happen by returning a custom {@link Comparator} in
* {@link #getOrderByComparator(Predicate, EvaluationContext)}.
*
* @param predicate
* predicate (for this evaluator type) which is evaluated
* @param context
* helper class which provides access to various elements of the
* query evaluation
* @return one or multiple relative paths to JCR properties or
* null
*/
String[] getOrderByProperties(Predicate predicate, EvaluationContext context);
/**
* Returns a comparator that will be used to "manually" sort the result
* after running the xpath query and after filtering via
* {@link #includes(Predicate, Row, EvaluationContext)} happened. This can
* be expensive and if possible,
* {@link #getOrderByProperties(Predicate, EvaluationContext)} (which is used
* for XPath order by) should be used. Result can be null
.
*
* @param predicate
* predicate (for this evaluator type) which is evaluated
* @param context
* helper class which provides access to various elements of the
* query evaluation
* @return a custom comparator for the given predicate or null
*/
Comparator getOrderByComparator(Predicate predicate, EvaluationContext context);
/**
* Returns a {@link FacetExtractor} that is used to create a {@link Facet}
* that maps to the given predicate. There are built-in extractor
* implementations that can be used (eg.
* {@link DistinctValuesFacetExtractor} which automatically creates a Facet
* with buckets based on the distinct values of a certain property).
*
*
* This method will only be called when the API user actually requests the
* facets from the search result using {@link SearchResult#getFacets()}.
*
*
* Important note: this object (the PredicateEvaluator) as an OSGi
* component instance will be released before the returned FacetExtractor is
* used, ie. before any method is called on it. This lazy usage of the
* extractor is needed, because during query execution it cannot be known if
* {@link SearchResult#getFacets()} will be called by the client afterwards.
* Thus be careful if you return an inner or anonymous class that uses
* members of this evaluator which are references to other OSGi components -
* at the time of facet extraction, these will be effectively
* null
. Thus you should retrieve information from the service
* while this method is called and store the result in the returned
* FacetExtractor object. This also means that you cannot directly use OSGi
* references in a FacetExtractor at all (they are not OSGi components).
*
* @param predicate
* predicate (for this evaluator type) which is evaluated
* @param context
* helper class which provides access to various elements of the
* query evaluation
* @return a {@link FacetExtractor} that is used to create a {@link Facet}
* or null
if no extractor shall be provided
*/
FacetExtractor getFacetExtractor(Predicate predicate, EvaluationContext context);
}