Skip to content

Commit 344e2de

Browse files
handle combined queries for inference and non-inference fields
1 parent 44ca30b commit 344e2de

File tree

2 files changed

+100
-25
lines changed

2 files changed

+100
-25
lines changed

x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/queries/SemanticMultiMatchQueryRewriteInterceptor.java

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -86,25 +86,31 @@ protected QueryBuilder buildCombinedInferenceAndNonInferenceQuery(
8686
Float fieldWeight
8787
) {
8888
assert (queryBuilder instanceof MultiMatchQueryBuilder);
89-
MultiMatchQueryBuilder originalMultiMatchQueryBuilder = (MultiMatchQueryBuilder) queryBuilder;
90-
91-
MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder(indexInformation.fieldName(), getQuery(queryBuilder));
92-
93-
// Create a copy for non-inference fields with only this specific field
94-
// MultiMatchQueryBuilder multiMatchQueryBuilder = createSingleFieldMultiMatch(
95-
// originalMultiMatchQueryBuilder,
96-
// indexInformation.fieldName()
97-
// );
89+
MultiMatchQueryBuilder multiMatchQueryBuilder = (MultiMatchQueryBuilder) queryBuilder;
9890

9991
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
92+
boolQueryBuilder.should(
93+
createSemanticSubQuery(indexInformation.getInferenceIndices(), indexInformation.fieldName(), (String) multiMatchQueryBuilder.value())
94+
);
10095

101-
// Add semantic query for inference indices
10296
boolQueryBuilder.should(
103-
createSemanticSubQuery(indexInformation.getInferenceIndices(), indexInformation.fieldName(), getQuery(matchQueryBuilder))
97+
createMatchSubQuery(
98+
indexInformation.nonInferenceIndices(),
99+
indexInformation.fieldName(),
100+
(String) multiMatchQueryBuilder.value()
101+
)
104102
);
105103

106-
// Add regular query for non-inference indices
107-
boolQueryBuilder.should(createSubQueryForIndices(indexInformation.nonInferenceIndices(), matchQueryBuilder));
104+
105+
QueryBuilder nonSemanticFieldQuery = buildNonSemanticFieldQuery(
106+
queryBuilder,
107+
indexInformation.fieldName(),
108+
fieldWeight
109+
);
110+
// boolQueryBuilder.should(
111+
// createSubQueryForIndices(indexInformation.nonInferenceIndices(), nonSemanticFieldQuery)
112+
// );
113+
// boolQueryBuilder.should(createSubQueryForIndices(indexInformation.nonInferenceIndices(), multiMatchQueryBuilder));
108114

109115
if (fieldWeight != null && fieldWeight.equals(1.0f) == false) {
110116
boolQueryBuilder.boost(fieldWeight);

x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/queries/SemanticQueryRewriteInterceptor.java

Lines changed: 81 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.elasticsearch.cluster.metadata.InferenceFieldMetadata;
1313
import org.elasticsearch.index.mapper.IndexFieldMapper;
1414
import org.elasticsearch.index.query.BoolQueryBuilder;
15+
import org.elasticsearch.index.query.MatchQueryBuilder;
1516
import org.elasticsearch.index.query.QueryBuilder;
1617
import org.elasticsearch.index.query.QueryRewriteContext;
1718
import org.elasticsearch.index.query.TermsQueryBuilder;
@@ -41,25 +42,71 @@ public QueryBuilder interceptAndRewrite(QueryRewriteContext context, QueryBuilde
4142
return queryBuilder;
4243
}
4344

45+
if (fieldNamesWithWeights.size() > 1) {
46+
// Multi-field query, so return the original query.
47+
return handleMultiFieldQuery(queryBuilder, fieldNamesWithWeights, resolvedIndices);
48+
}
49+
50+
String fieldName = fieldNamesWithWeights.keySet().iterator().next();
51+
Float weight = fieldNamesWithWeights.get(fieldName);
52+
InferenceIndexInformationForField indexInformation = resolveIndicesForField(fieldName, resolvedIndices);
53+
if (indexInformation.getInferenceIndices().isEmpty()) {
54+
// No inference fields were identified, so return the original query.
55+
return queryBuilder;
56+
} else if (indexInformation.nonInferenceIndices().isEmpty() == false) {
57+
// Combined case where the field name requested by this query contains both
58+
// semantic_text and non-inference fields, so we have to combine queries per index
59+
// containing each field type.
60+
return buildCombinedInferenceAndNonInferenceQuery(queryBuilder, indexInformation, weight);
61+
} else {
62+
// The only fields we've identified are inference fields (e.g. semantic_text),
63+
// so rewrite the entire query to work on a semantic_text field.
64+
return buildInferenceQuery(queryBuilder, indexInformation, weight);
65+
}
66+
}
67+
68+
/**
69+
* Handle multi-field queries (new logic)
70+
*/
71+
private QueryBuilder handleMultiFieldQuery(
72+
QueryBuilder queryBuilder,
73+
Map<String, Float> fieldNamesWithWeights,
74+
ResolvedIndices resolvedIndices
75+
) {
4476
BoolQueryBuilder finalQueryBuilder = new BoolQueryBuilder();
45-
for (Map.Entry<String, Float> fieldSet : fieldNamesWithWeights.entrySet()) {
46-
String fieldName = fieldSet.getKey();
47-
Float fieldWeight = fieldSet.getValue();
77+
boolean hasAnySemanticFields = false;
78+
79+
for (Map.Entry<String, Float> fieldEntry : fieldNamesWithWeights.entrySet()) {
80+
String fieldName = fieldEntry.getKey();
81+
Float fieldWeight = fieldEntry.getValue();
4882
InferenceIndexInformationForField indexInformation = resolveIndicesForField(fieldName, resolvedIndices);
83+
4984
if (indexInformation.getInferenceIndices().isEmpty()) {
50-
// No inference fields were identified, so return the original query.
51-
finalQueryBuilder.should(queryBuilder);
85+
// Pure non-semantic field - create individual match query
86+
QueryBuilder nonSemanticQuery = createMatchSubQuery(
87+
indexInformation.nonInferenceIndices(),
88+
fieldName,
89+
getQuery(queryBuilder));
90+
finalQueryBuilder.should(nonSemanticQuery);
5291
} else if (indexInformation.nonInferenceIndices().isEmpty() == false) {
53-
// Combined case where the field name requested by this query contains both
54-
// semantic_text and non-inference fields, so we have to combine queries per index
55-
// containing each field type.
56-
finalQueryBuilder.should(buildCombinedInferenceAndNonInferenceQuery(queryBuilder, indexInformation, fieldWeight));
92+
// Mixed semantic/non-semantic field - use combined approach
93+
QueryBuilder combinedQuery = buildCombinedInferenceAndNonInferenceQuery(queryBuilder, indexInformation, fieldWeight);
94+
finalQueryBuilder.should(combinedQuery);
95+
hasAnySemanticFields = true;
5796
} else {
58-
// The only fields we've identified are inference fields (e.g. semantic_text),
59-
// so rewrite the entire query to work on a semantic_text field.
60-
finalQueryBuilder.should(buildInferenceQuery(queryBuilder, indexInformation, fieldWeight));
97+
// Pure semantic field - create semantic query
98+
QueryBuilder semanticQuery = buildInferenceQuery(queryBuilder, indexInformation, fieldWeight);
99+
finalQueryBuilder.should(semanticQuery);
100+
hasAnySemanticFields = true;
61101
}
62102
}
103+
104+
// If no semantic fields were found, return original query
105+
if (hasAnySemanticFields == false) {
106+
return queryBuilder;
107+
}
108+
109+
// finalQueryBuilder.minimumShouldMatch(1);
63110
return finalQueryBuilder;
64111
}
65112

@@ -125,6 +172,28 @@ private InferenceIndexInformationForField resolveIndicesForField(String fieldNam
125172
return new InferenceIndexInformationForField(fieldName, inferenceIndicesMetadata, nonInferenceIndices);
126173
}
127174

175+
/**
176+
* Build a non-semantic field query (for multi-field scenarios)
177+
*/
178+
protected QueryBuilder buildNonSemanticFieldQuery(QueryBuilder queryBuilder, String fieldName, Float fieldWeight) {
179+
// Default implementation - subclasses can override for specific query types
180+
String query = getQuery(queryBuilder);
181+
MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder(fieldName, query);
182+
matchQueryBuilder.boost(fieldWeight);
183+
return matchQueryBuilder;
184+
}
185+
186+
protected QueryBuilder createMatchSubQuery(Collection<String> indices, String fieldName, String queryText) {
187+
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
188+
MatchQueryBuilder matchQuery = new MatchQueryBuilder(fieldName, queryText);
189+
// if (fieldWeight != null && !fieldWeight.equals(1.0f)) {
190+
// matchQuery.boost(fieldWeight);
191+
// }
192+
boolQueryBuilder.must(matchQuery);
193+
boolQueryBuilder.filter(new TermsQueryBuilder(IndexFieldMapper.NAME, indices));
194+
return boolQueryBuilder;
195+
}
196+
128197
protected QueryBuilder createSubQueryForIndices(Collection<String> indices, QueryBuilder queryBuilder) {
129198
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
130199
boolQueryBuilder.must(queryBuilder);

0 commit comments

Comments
 (0)