Skip to content
Merged
Show file tree
Hide file tree
Changes from 81 commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
62e8aa7
Added query name to inference field metadata
Mikep86 Aug 22, 2024
43e65eb
Fix build error
Mikep86 Aug 23, 2024
39eaa56
Added query builder service
Mikep86 Aug 23, 2024
e633aa6
Add query builder service to query rewrite context
Mikep86 Aug 23, 2024
9c06b6e
Updated match query to support querying semantic text fields
Mikep86 Aug 23, 2024
db02010
Fix build error
Mikep86 Aug 23, 2024
6956ffb
Fix NPE
kderusso Nov 25, 2024
3235130
Update the POC to rewrite to a bool query when combined inference and…
kderusso Nov 25, 2024
05638af
Separate clause for each inference index (to avoid inference ID clashes)
kderusso Nov 25, 2024
74b4346
Simplify query builder service concept to a single default inference …
kderusso Nov 27, 2024
720be53
Rename QueryBuilderService, remove query name from inference metadata
kderusso Nov 27, 2024
6197541
Fix too many rewrite rounds error by injecting booleans in constructo…
kderusso Dec 2, 2024
c8a576c
Fix test compilation errors
kderusso Dec 2, 2024
a1c3e66
Merge branch 'main' into kderusso/semantic-text-match-query-support
kderusso Dec 2, 2024
bcb93c3
Fix tests
kderusso Dec 2, 2024
6e6e88f
Add yaml test for semantic match
kderusso Dec 2, 2024
727e0f1
Add NodeFeature
kderusso Dec 2, 2024
185afa0
Fix license headers
kderusso Dec 2, 2024
b4dc5d4
Merge branch 'main' into kderusso/semantic-text-match-query-support
kderusso Dec 2, 2024
4211f24
Spotless
kderusso Dec 2, 2024
d9bc033
Updated getClass comparison in MatchQueryBuilder
kderusso Dec 3, 2024
f9e283f
Cleanup
kderusso Dec 3, 2024
6fe8d66
Add Mock Inference Query Builder Service
kderusso Dec 3, 2024
f99ae91
Merge branch 'main' into kderusso/semantic-text-match-query-support
kderusso Dec 3, 2024
f219ff3
Spotless
kderusso Dec 3, 2024
4232154
Cleanup
kderusso Dec 3, 2024
1e2fb8f
Update docs/changelog/117839.yaml
kderusso Dec 3, 2024
84901e2
Update changelog
kderusso Dec 3, 2024
4b5ca9f
Replace the default inference query builder with a query rewrite inte…
kderusso Dec 4, 2024
11b3efa
Cleanup
kderusso Dec 4, 2024
ec5d333
Some more cleanup/renames
kderusso Dec 4, 2024
5c6703e
Some more cleanup/renames
kderusso Dec 4, 2024
fcd4c85
Spotless
kderusso Dec 4, 2024
296a28c
Merge branch 'main' into kderusso/semantic-text-match-query-support
kderusso Dec 4, 2024
c7f90ae
Checkstyle
kderusso Dec 4, 2024
9640ad1
Convert List<QueryRewriteInterceptor> to Map keyed on query name, err…
kderusso Dec 5, 2024
bc7f735
PR feedback - remove check on QueryRewriteContext class only
kderusso Dec 5, 2024
9b7b7d2
PR feedback
kderusso Dec 5, 2024
b97d148
Remove intercept flag from MatchQueryBuilder and replace with wrapper
kderusso Dec 5, 2024
3be4e83
Move feature to test feature
kderusso Dec 5, 2024
078285f
Merge branch 'main' into kderusso/semantic-text-match-query-support
kderusso Dec 5, 2024
66cdd3d
Merge branch 'main' into kderusso/semantic-text-match-query-support
kderusso Dec 6, 2024
54989ab
Merge branch 'main' into kderusso/semantic-text-match-query-support
kderusso Dec 6, 2024
b3b2507
Ensure interception happens only once
kderusso Dec 6, 2024
1c696d0
Rename InterceptedQueryBuilderWrapper to AbstractQueryBuilderWrapper
kderusso Dec 6, 2024
b09e1d0
Add lenient field to SemanticQueryBuilder
kderusso Dec 6, 2024
916eb73
Clean up yaml test
kderusso Dec 6, 2024
83ce34f
Add TODO comment
kderusso Dec 6, 2024
78d7b59
Add comment
kderusso Dec 6, 2024
680c7d9
Spotless
kderusso Dec 6, 2024
021d592
Rename AbstractQueryBuilderWrapper back to InterceptedQueryBuilderWra…
kderusso Dec 6, 2024
cfa288a
Spotless
kderusso Dec 6, 2024
ba6890d
Didn't mean to commit that
kderusso Dec 6, 2024
1e75ab8
Remove static class wrapping the InterceptedQueryBuilderWrapper
kderusso Dec 9, 2024
f6b5ab5
Make InterceptedQueryBuilderWrapper part of QueryRewriteInterceptor
kderusso Dec 9, 2024
c998f1c
Refactor the interceptor to be an internal plugin that cannot be used…
kderusso Dec 9, 2024
3c59e61
Fix tests
kderusso Dec 9, 2024
6c600b9
Merge branch 'main' into kderusso/semantic-text-match-query-support
kderusso Dec 9, 2024
b7fd486
Spotless
kderusso Dec 9, 2024
52babac
Minor cleanup
kderusso Dec 9, 2024
68f8e47
C'mon spotless
kderusso Dec 9, 2024
bd511b8
Test spotless
kderusso Dec 9, 2024
068c4bb
Cleanup InternalQueryRewriter
kderusso Dec 9, 2024
7383ac6
Change if statement to assert
kderusso Dec 9, 2024
08aadec
Simplify template of InterceptedQueryBuilderWrapper
kderusso Dec 10, 2024
77a775b
Change constructor of InterceptedQueryBuilderWrapper
kderusso Dec 10, 2024
21d859f
Refactor InterceptedQueryBuilderWrapper to extend QueryBuilder
kderusso Dec 10, 2024
e52625b
Cleanup
kderusso Dec 10, 2024
24dc240
Add test
kderusso Dec 10, 2024
53bce75
Spotless
kderusso Dec 10, 2024
fa17a73
Merge from main
kderusso Dec 10, 2024
af4cc21
Rename rewrite to interceptAndRewrite in QueryRewriteInterceptor
kderusso Dec 10, 2024
2830b2d
DOESN'T WORK - for testing
kderusso Dec 10, 2024
7bc830a
Add comment
kderusso Dec 10, 2024
0d6ad3b
Getting closer - match on single typed fields works now
kderusso Dec 10, 2024
a4d2030
Deleted line by mistake
kderusso Dec 10, 2024
7dfa0a2
Checkstyle
kderusso Dec 10, 2024
b6b7ab4
Merge branch 'main' into kderusso/semantic-text-match-query-support
kderusso Dec 10, 2024
a989a19
Fix over-aggressive IntelliJ Refactor/Rename
kderusso Dec 10, 2024
c3913ac
And another one
kderusso Dec 10, 2024
cc6fe01
Move SemanticMatchQueryRewriteInterceptor.SEMANTIC_MATCH_QUERY_REWRIT…
kderusso Dec 10, 2024
6a92936
PR feedback
kderusso Dec 11, 2024
f4c26ae
Require query name with no default
kderusso Dec 11, 2024
5d13449
Merge branch 'main' into kderusso/semantic-text-match-query-support
kderusso Dec 11, 2024
f20a353
PR feedback & update test
kderusso Dec 11, 2024
3e3cb2e
Merge branch 'main' into kderusso/semantic-text-match-query-support
kderusso Dec 11, 2024
278e860
Add rewrite test
kderusso Dec 11, 2024
1fc6125
Update server/src/main/java/org/elasticsearch/index/query/InnerHitCon…
kderusso Dec 12, 2024
f6f57bb
Update test
kderusso Dec 12, 2024
c0092e8
Merge branch 'main' into kderusso/semantic-text-match-query-support
kderusso Dec 12, 2024
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/changelog/117839.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 117839
summary: Add match support for `semantic_text` fields
area: "Search"
type: enhancement
issues: []
2 changes: 1 addition & 1 deletion server/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -479,5 +479,5 @@
exports org.elasticsearch.lucene.spatial;
exports org.elasticsearch.inference.configuration;
exports org.elasticsearch.monitor.metrics;

exports org.elasticsearch.plugins.internal.rewriter to org.elasticsearch.inference;
}
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ static TransportVersion def(int id) {
public static final TransportVersion NEW_REFRESH_CLUSTER_BLOCK = def(8_803_00_0);
public static final TransportVersion RETRIES_AND_OPERATIONS_IN_BLOBSTORE_STATS = def(8_804_00_0);
public static final TransportVersion ADD_DATA_STREAM_OPTIONS_TO_TEMPLATES = def(8_805_00_0);
public static final TransportVersion SEMANTIC_QUERY_LENIENT = def(8_806_00_0);

/*
* STOP! READ THIS FIRST! No, really,
Expand Down
7 changes: 5 additions & 2 deletions server/src/main/java/org/elasticsearch/index/IndexModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import org.elasticsearch.indices.fielddata.cache.IndicesFieldDataCache;
import org.elasticsearch.indices.recovery.RecoveryState;
import org.elasticsearch.plugins.IndexStorePlugin;
import org.elasticsearch.plugins.internal.rewriter.QueryRewriteInterceptor;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.search.aggregations.support.ValuesSourceRegistry;
import org.elasticsearch.threadpool.ThreadPool;
Expand Down Expand Up @@ -478,7 +479,8 @@ public IndexService newIndexService(
IdFieldMapper idFieldMapper,
ValuesSourceRegistry valuesSourceRegistry,
IndexStorePlugin.IndexFoldersDeletionListener indexFoldersDeletionListener,
Map<String, IndexStorePlugin.SnapshotCommitSupplier> snapshotCommitSuppliers
Map<String, IndexStorePlugin.SnapshotCommitSupplier> snapshotCommitSuppliers,
QueryRewriteInterceptor queryRewriteInterceptor
) throws IOException {
final IndexEventListener eventListener = freeze();
Function<IndexService, CheckedFunction<DirectoryReader, DirectoryReader, IOException>> readerWrapperFactory = indexReaderWrapper
Expand Down Expand Up @@ -540,7 +542,8 @@ public IndexService newIndexService(
indexFoldersDeletionListener,
snapshotCommitSupplier,
indexCommitListener.get(),
mapperMetrics
mapperMetrics,
queryRewriteInterceptor
);
success = true;
return indexService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
import org.elasticsearch.indices.fielddata.cache.IndicesFieldDataCache;
import org.elasticsearch.indices.recovery.RecoveryState;
import org.elasticsearch.plugins.IndexStorePlugin;
import org.elasticsearch.plugins.internal.rewriter.QueryRewriteInterceptor;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.search.aggregations.support.ValuesSourceRegistry;
import org.elasticsearch.threadpool.ThreadPool;
Expand Down Expand Up @@ -162,6 +163,7 @@ public class IndexService extends AbstractIndexComponent implements IndicesClust
private final Supplier<Sort> indexSortSupplier;
private final ValuesSourceRegistry valuesSourceRegistry;
private final MapperMetrics mapperMetrics;
private final QueryRewriteInterceptor queryRewriteInterceptor;

@SuppressWarnings("this-escape")
public IndexService(
Expand Down Expand Up @@ -196,7 +198,8 @@ public IndexService(
IndexStorePlugin.IndexFoldersDeletionListener indexFoldersDeletionListener,
IndexStorePlugin.SnapshotCommitSupplier snapshotCommitSupplier,
Engine.IndexCommitListener indexCommitListener,
MapperMetrics mapperMetrics
MapperMetrics mapperMetrics,
QueryRewriteInterceptor queryRewriteInterceptor
) {
super(indexSettings);
assert indexCreationContext != IndexCreationContext.RELOAD_ANALYZERS
Expand Down Expand Up @@ -271,6 +274,7 @@ public IndexService(
this.indexingOperationListeners = Collections.unmodifiableList(indexingOperationListeners);
this.indexCommitListener = indexCommitListener;
this.mapperMetrics = mapperMetrics;
this.queryRewriteInterceptor = queryRewriteInterceptor;
try (var ignored = threadPool.getThreadContext().clearTraceContext()) {
// kick off async ops for the first shard in this index
this.refreshTask = new AsyncRefreshTask(this);
Expand Down Expand Up @@ -802,6 +806,7 @@ public QueryRewriteContext newQueryRewriteContext(
allowExpensiveQueries,
scriptService,
null,
null,
null
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.elasticsearch.common.lucene.BytesRefs;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.SuggestingErrorOnUnknown;
import org.elasticsearch.plugins.internal.rewriter.QueryRewriteInterceptor;
import org.elasticsearch.xcontent.AbstractObjectParser;
import org.elasticsearch.xcontent.FilterXContentParser;
import org.elasticsearch.xcontent.FilterXContentParserWrapper;
Expand Down Expand Up @@ -278,6 +279,14 @@ protected static List<QueryBuilder> readQueries(StreamInput in) throws IOExcepti

@Override
public final QueryBuilder rewrite(QueryRewriteContext queryRewriteContext) throws IOException {
QueryRewriteInterceptor queryRewriteInterceptor = queryRewriteContext.getQueryRewriteInterceptor();
if (queryRewriteInterceptor != null) {
var rewritten = queryRewriteInterceptor.interceptAndRewrite(queryRewriteContext, this);
if (rewritten != this) {
return new InterceptedQueryBuilderWrapper(rewritten);
}
}

QueryBuilder rewritten = doRewrite(queryRewriteContext);
if (rewritten == this) {
return rewritten;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ public CoordinatorRewriteContext(
null,
null,
null,
null,
null
);
this.dateFieldRangeInfo = dateFieldRangeInfo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ public InnerHitBuilder innerHitBuilder() {
public static void extractInnerHits(QueryBuilder query, Map<String, InnerHitContextBuilder> innerHitBuilders) {
if (query instanceof AbstractQueryBuilder) {
((AbstractQueryBuilder<?>) query).extractInnerHitBuilders(innerHitBuilders);
} else if (query instanceof InterceptedQueryBuilderWrapper) {
// Unwrap an intercepted query here
extractInnerHits(((InterceptedQueryBuilderWrapper) query).queryBuilder, innerHitBuilders);
} else {
throw new IllegalStateException(
"provided query builder [" + query.getClass() + "] class should inherit from AbstractQueryBuilder, but it doesn't"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

package org.elasticsearch.index.query;

import org.apache.lucene.search.Query;
import org.elasticsearch.TransportVersion;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.plugins.internal.rewriter.QueryRewriteInterceptor;
import org.elasticsearch.xcontent.XContentBuilder;

import java.io.IOException;
import java.util.Objects;

/**
* Wrapper for instances of {@link QueryBuilder} that have been intercepted using the {@link QueryRewriteInterceptor} to
* break out of the rewrite phase. These instances are unwrapped on serialization.
*/
class InterceptedQueryBuilderWrapper implements QueryBuilder {

protected final QueryBuilder queryBuilder;

InterceptedQueryBuilderWrapper(QueryBuilder queryBuilder) {
super();
this.queryBuilder = queryBuilder;
}

@Override
public QueryBuilder rewrite(QueryRewriteContext queryRewriteContext) throws IOException {
QueryRewriteInterceptor queryRewriteInterceptor = queryRewriteContext.getQueryRewriteInterceptor();
try {
queryRewriteContext.setQueryRewriteInterceptor(null);
QueryBuilder rewritten = queryBuilder.rewrite(queryRewriteContext);
if (rewritten != queryBuilder) {
return new InterceptedQueryBuilderWrapper(rewritten);
}
return this;
} finally {
queryRewriteContext.setQueryRewriteInterceptor(queryRewriteInterceptor);
}
}

@Override
public String getWriteableName() {
return queryBuilder.getWriteableName();
}

@Override
public TransportVersion getMinimalSupportedVersion() {
return queryBuilder.getMinimalSupportedVersion();
}

@Override
public Query toQuery(SearchExecutionContext context) throws IOException {
return queryBuilder.toQuery(context);
}

@Override
public QueryBuilder queryName(String queryName) {
return queryBuilder.queryName(queryName);
}

@Override
public String queryName() {
return queryBuilder.queryName();
}

@Override
public float boost() {
return queryBuilder.boost();
}

@Override
public QueryBuilder boost(float boost) {
return queryBuilder.boost(boost);
}

@Override
public String getName() {
return queryBuilder.getName();
}

@Override
public void writeTo(StreamOutput out) throws IOException {
queryBuilder.writeTo(out);
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return queryBuilder.toXContent(builder, params);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o instanceof InterceptedQueryBuilderWrapper == false) return false;
return Objects.equals(queryBuilder, ((InterceptedQueryBuilderWrapper) o).queryBuilder);
}

@Override
public int hashCode() {
return Objects.hashCode(queryBuilder);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.elasticsearch.index.mapper.MappingLookup;
import org.elasticsearch.index.mapper.SourceFieldMapper;
import org.elasticsearch.index.mapper.TextFieldMapper;
import org.elasticsearch.plugins.internal.rewriter.QueryRewriteInterceptor;
import org.elasticsearch.script.ScriptCompiler;
import org.elasticsearch.search.aggregations.support.ValuesSourceRegistry;
import org.elasticsearch.search.builder.PointInTimeBuilder;
Expand Down Expand Up @@ -70,6 +71,7 @@ public class QueryRewriteContext {
protected Predicate<String> allowedFields;
private final ResolvedIndices resolvedIndices;
private final PointInTimeBuilder pit;
private QueryRewriteInterceptor queryRewriteInterceptor;

public QueryRewriteContext(
final XContentParserConfiguration parserConfiguration,
Expand All @@ -86,7 +88,8 @@ public QueryRewriteContext(
final BooleanSupplier allowExpensiveQueries,
final ScriptCompiler scriptService,
final ResolvedIndices resolvedIndices,
final PointInTimeBuilder pit
final PointInTimeBuilder pit,
final QueryRewriteInterceptor queryRewriteInterceptor
) {

this.parserConfiguration = parserConfiguration;
Expand All @@ -105,6 +108,7 @@ public QueryRewriteContext(
this.scriptService = scriptService;
this.resolvedIndices = resolvedIndices;
this.pit = pit;
this.queryRewriteInterceptor = queryRewriteInterceptor;
}

public QueryRewriteContext(final XContentParserConfiguration parserConfiguration, final Client client, final LongSupplier nowInMillis) {
Expand All @@ -123,6 +127,7 @@ public QueryRewriteContext(final XContentParserConfiguration parserConfiguration
null,
null,
null,
null,
null
);
}
Expand All @@ -132,7 +137,8 @@ public QueryRewriteContext(
final Client client,
final LongSupplier nowInMillis,
final ResolvedIndices resolvedIndices,
final PointInTimeBuilder pit
final PointInTimeBuilder pit,
final QueryRewriteInterceptor queryRewriteInterceptor
) {
this(
parserConfiguration,
Expand All @@ -149,7 +155,8 @@ public QueryRewriteContext(
null,
null,
resolvedIndices,
pit
pit,
queryRewriteInterceptor
);
}

Expand Down Expand Up @@ -428,4 +435,13 @@ public String getTierPreference() {
// It was decided we should only test the first of these potentially multiple preferences.
return value.split(",")[0].trim();
}

public QueryRewriteInterceptor getQueryRewriteInterceptor() {
return queryRewriteInterceptor;
}

public void setQueryRewriteInterceptor(QueryRewriteInterceptor queryRewriteInterceptor) {
this.queryRewriteInterceptor = queryRewriteInterceptor;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ private SearchExecutionContext(
allowExpensiveQueries,
scriptService,
null,
null,
null
);
this.shardId = shardId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@
import org.elasticsearch.plugins.FieldPredicate;
import org.elasticsearch.plugins.IndexStorePlugin;
import org.elasticsearch.plugins.PluginsService;
import org.elasticsearch.plugins.internal.rewriter.QueryRewriteInterceptor;
import org.elasticsearch.repositories.RepositoriesService;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.search.aggregations.support.ValuesSourceRegistry;
Expand Down Expand Up @@ -262,6 +263,7 @@ public class IndicesService extends AbstractLifecycleComponent
private final MapperMetrics mapperMetrics;
private final PostRecoveryMerger postRecoveryMerger;
private final List<SearchOperationListener> searchOperationListeners;
private final QueryRewriteInterceptor queryRewriteInterceptor;

@Override
protected void doStart() {
Expand Down Expand Up @@ -330,6 +332,7 @@ public void onRemoval(ShardId shardId, String fieldName, boolean wasEvicted, lon
this.indexFoldersDeletionListeners = new CompositeIndexFoldersDeletionListener(builder.indexFoldersDeletionListeners);
this.snapshotCommitSuppliers = builder.snapshotCommitSuppliers;
this.requestCacheKeyDifferentiator = builder.requestCacheKeyDifferentiator;
this.queryRewriteInterceptor = builder.queryRewriteInterceptor;
this.mapperMetrics = builder.mapperMetrics;
// doClose() is called when shutting down a node, yet there might still be ongoing requests
// that we need to wait for before closing some resources such as the caches. In order to
Expand Down Expand Up @@ -779,7 +782,8 @@ private synchronized IndexService createIndexService(
idFieldMappers.apply(idxSettings.getMode()),
valuesSourceRegistry,
indexFoldersDeletionListeners,
snapshotCommitSuppliers
snapshotCommitSuppliers,
queryRewriteInterceptor
);
}

Expand Down Expand Up @@ -1766,7 +1770,7 @@ public AliasFilter buildAliasFilter(ClusterState state, String index, Set<Resolv
* Returns a new {@link QueryRewriteContext} with the given {@code now} provider
*/
public QueryRewriteContext getRewriteContext(LongSupplier nowInMillis, ResolvedIndices resolvedIndices, PointInTimeBuilder pit) {
return new QueryRewriteContext(parserConfig, client, nowInMillis, resolvedIndices, pit);
return new QueryRewriteContext(parserConfig, client, nowInMillis, resolvedIndices, pit, queryRewriteInterceptor);
}

public DataRewriteContext getDataRewriteContext(LongSupplier nowInMillis) {
Expand Down
Loading