Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,13 @@ private BaseFilterOperator constructPhysicalOperator(FilterContext filter, int n
// Check if case-insensitive flag is present
RegexpLikePredicate regexpLikePredicate = (RegexpLikePredicate) predicate;
boolean caseInsensitive = regexpLikePredicate.isCaseInsensitive();
// IFST/FST evaluators are dict-id based and can only be consumed by sorted/inverted-index filter
// operators. If neither is available for this segment, the planner will fall through to
// ScanBasedFilterOperator, which reads raw values from the forward index and cannot service a
// dict-id evaluator (applySV(String) throws on BaseDictionaryBasedPredicateEvaluator). In that
// case, route through the raw-value evaluator instead.
if (caseInsensitive) {
if (dataSource.getIFSTIndex() != null) {
if (dataSource.getIFSTIndex() != null && canConsumeDictIdEvaluator(dataSource, _queryContext)) {
predicateEvaluator =
IFSTBasedRegexpPredicateEvaluatorFactory.newIFSTBasedEvaluator(regexpLikePredicate,
dataSource.getIFSTIndex(), dataSource.getDictionary());
Expand All @@ -319,7 +324,7 @@ private BaseFilterOperator constructPhysicalOperator(FilterContext filter, int n
PredicateEvaluatorProvider.getPredicateEvaluator(predicate, dataSource, _queryContext);
}
} else {
if (dataSource.getFSTIndex() != null) {
if (dataSource.getFSTIndex() != null && canConsumeDictIdEvaluator(dataSource, _queryContext)) {
predicateEvaluator = FSTBasedRegexpPredicateEvaluatorFactory.newFSTBasedEvaluator(regexpLikePredicate,
dataSource.getFSTIndex(), dataSource.getDictionary());
} else {
Expand Down Expand Up @@ -433,6 +438,30 @@ private BaseFilterOperator constructFilteredVectorOperator(FilterContext filter,
numDocs, true);
}

/// Returns true if a dictionary-id based REGEXP_LIKE evaluator (e.g. IFST/FST/DictId) can be consumed at run time
/// either by:
/// 1. A sorted-index filter operator (`SortedIndexBasedFilterOperator`).
/// 2. An inverted-index filter operator (`InvertedIndexFilterOperator`).
/// 3. The scan filter operator when the forward index is dictionary-encoded (`DictIdMatcher` in
/// `SVScanDocIdIterator` reads dict ids from the forward index and calls `applySV(int dictId)`).
///
/// When false, the scan path will pick a typed raw matcher (e.g. `StringMatcher`) and call
/// `applySV(<rawType>)`, which a dict-id evaluator cannot service. In that case the IFST/FST evaluator should be
/// skipped in favor of the raw-value evaluator
/// (`RegexpLikePredicateEvaluatorFactory#newRawValueBasedEvaluator`).
private static boolean canConsumeDictIdEvaluator(DataSource dataSource, QueryContext queryContext) {
if (dataSource.getDataSourceMetadata().isSorted()
&& queryContext.isIndexUseAllowed(dataSource, FieldConfig.IndexType.SORTED)) {
return true;
}
if (dataSource.getInvertedIndex() != null
&& queryContext.isIndexUseAllowed(dataSource, FieldConfig.IndexType.INVERTED)) {
return true;
}
ForwardIndexReader<?> forwardIndex = dataSource.getForwardIndex();
return forwardIndex != null && forwardIndex.isDictionaryEncoded();
}

/**
* Returns true if the child list contains at least one non-VECTOR_SIMILARITY predicate
* (i.e., a real metadata filter sibling).
Expand Down
Loading