1414import org .elasticsearch .index .query .BoolQueryBuilder ;
1515import org .elasticsearch .index .query .MultiMatchQueryBuilder ;
1616import org .elasticsearch .index .query .QueryBuilder ;
17+ import org .elasticsearch .index .query .QueryBuilders ;
1718import org .elasticsearch .index .query .QueryRewriteContext ;
1819import org .elasticsearch .index .query .TermsQueryBuilder ;
1920import org .elasticsearch .plugins .internal .rewriter .QueryRewriteInterceptor ;
@@ -43,9 +44,7 @@ public QueryBuilder interceptAndRewrite(QueryRewriteContext context, QueryBuilde
4344 }
4445
4546 if (queryBuilder instanceof MultiMatchQueryBuilder ) {
46- // This is a placeholder for the actual multi-field handling logic.
47- // Going forward, we will also send fieldNamesWithWeights and resolvedIndices
48- return handleMultiFieldQuery (queryBuilder );
47+ return handleMultiFieldQuery (queryBuilder , fieldsWithBoosts , resolvedIndices );
4948 }
5049
5150 String fieldName = fieldsWithBoosts .keySet ().iterator ().next ();
@@ -68,10 +67,86 @@ public QueryBuilder interceptAndRewrite(QueryRewriteContext context, QueryBuilde
6867 }
6968
7069 /**
71- * Handle multi-field queries
70+ * Handle multi-field queries by analyzing each field for semantic_text fields
71+ * and creating appropriate queries
7272 */
73- private QueryBuilder handleMultiFieldQuery (QueryBuilder queryBuilder ) {
74- return queryBuilder ;
73+ private QueryBuilder handleMultiFieldQuery (
74+ QueryBuilder queryBuilder ,
75+ Map <String , Float > fieldsWithBoosts ,
76+ ResolvedIndices resolvedIndices
77+ ) {
78+ assert (queryBuilder instanceof MultiMatchQueryBuilder );
79+ MultiMatchQueryBuilder multiMatchQueryBuilder = (MultiMatchQueryBuilder ) queryBuilder ;
80+ String queryText = getQuery (queryBuilder );
81+
82+ boolean hasSemanticField = false ;
83+ Map <String , InferenceIndexInformationForField > fieldInfoMap = new HashMap <>();
84+
85+ // Analyze each field to determine if it's semantic or not
86+ for (Map .Entry <String , Float > fieldEntry : fieldsWithBoosts .entrySet ()) {
87+ String fieldName = fieldEntry .getKey ();
88+ InferenceIndexInformationForField indexInfo = resolveIndicesForField (fieldName , resolvedIndices );
89+ fieldInfoMap .put (fieldName , indexInfo );
90+
91+ if (indexInfo .getInferenceIndices ().isEmpty () ==false ) {
92+ hasSemanticField = true ;
93+ }
94+ }
95+
96+ // If no semantic fields were found, return the original query
97+ if (hasSemanticField == false ) {
98+ return queryBuilder ;
99+ }
100+
101+ // Create a combined query
102+ BoolQueryBuilder combinedQuery = new BoolQueryBuilder ();
103+
104+ // Apply the MultiMatch type and tie-breaker
105+ MultiMatchQueryBuilder .Type type = multiMatchQueryBuilder .type ();
106+ Float tieBreaker = multiMatchQueryBuilder .tieBreaker ();
107+ boolean shouldUseTieBreaker = (tieBreaker != null );
108+
109+
110+ Map <String , Float > nonSemanticFields = new HashMap <>();
111+ for (Map .Entry <String , Float > fieldEntry : fieldsWithBoosts .entrySet ()) {
112+ String fieldName = fieldEntry .getKey ();
113+ Float fieldBoost = fieldEntry .getValue ();
114+ InferenceIndexInformationForField indexInfo = fieldInfoMap .get (fieldName );
115+
116+ if (indexInfo .getInferenceIndices ().isEmpty ()) {
117+ nonSemanticFields .put (fieldName , fieldBoost );
118+ } else if (indexInfo .nonInferenceIndices ().isEmpty ()) {
119+ QueryBuilder semanticQuery = buildInferenceQuery (queryBuilder , indexInfo , fieldBoost );
120+ if (shouldUseTieBreaker ) {
121+ semanticQuery .boost (semanticQuery .boost () * (type == MultiMatchQueryBuilder .Type .MOST_FIELDS ? 1.0f : tieBreaker ));
122+ }
123+ combinedQuery .should (semanticQuery );
124+ } else {
125+ QueryBuilder mixedQuery = buildCombinedInferenceAndNonInferenceQuery (queryBuilder , indexInfo , fieldBoost );
126+ if (shouldUseTieBreaker ) {
127+ mixedQuery .boost (mixedQuery .boost () * (type == MultiMatchQueryBuilder .Type .MOST_FIELDS ? 1.0f : tieBreaker ));
128+ }
129+ combinedQuery .should (mixedQuery );
130+ }
131+ }
132+
133+ if (nonSemanticFields .isEmpty () == false ) {
134+ MultiMatchQueryBuilder nonSemanticQuery = QueryBuilders .multiMatchQuery (queryText );
135+ nonSemanticQuery .fields (nonSemanticFields );
136+
137+ SemanticMultiMatchQueryRewriteInterceptor .copyMultiMatchConfiguration (multiMatchQueryBuilder , nonSemanticQuery );
138+
139+ if (shouldUseTieBreaker ) {
140+ nonSemanticQuery .boost (nonSemanticQuery .boost () * (type == MultiMatchQueryBuilder .Type .MOST_FIELDS ? 1.0f : tieBreaker ));
141+ }
142+
143+ combinedQuery .should (nonSemanticQuery );
144+ }
145+
146+ combinedQuery .boost (queryBuilder .boost ());
147+ combinedQuery .queryName (queryBuilder .queryName ());
148+
149+ return combinedQuery ;
75150 }
76151
77152 /**
0 commit comments