|
12 | 12 | import org.elasticsearch.cluster.metadata.InferenceFieldMetadata; |
13 | 13 | import org.elasticsearch.index.mapper.IndexFieldMapper; |
14 | 14 | import org.elasticsearch.index.query.BoolQueryBuilder; |
| 15 | +import org.elasticsearch.index.query.MatchQueryBuilder; |
15 | 16 | import org.elasticsearch.index.query.QueryBuilder; |
16 | 17 | import org.elasticsearch.index.query.QueryRewriteContext; |
17 | 18 | import org.elasticsearch.index.query.TermsQueryBuilder; |
@@ -41,25 +42,71 @@ public QueryBuilder interceptAndRewrite(QueryRewriteContext context, QueryBuilde |
41 | 42 | return queryBuilder; |
42 | 43 | } |
43 | 44 |
|
| 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 | + ) { |
44 | 76 | 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(); |
48 | 82 | InferenceIndexInformationForField indexInformation = resolveIndicesForField(fieldName, resolvedIndices); |
| 83 | + |
49 | 84 | 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); |
52 | 91 | } 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; |
57 | 96 | } 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; |
61 | 101 | } |
62 | 102 | } |
| 103 | + |
| 104 | + // If no semantic fields were found, return original query |
| 105 | + if (hasAnySemanticFields == false) { |
| 106 | + return queryBuilder; |
| 107 | + } |
| 108 | + |
| 109 | +// finalQueryBuilder.minimumShouldMatch(1); |
63 | 110 | return finalQueryBuilder; |
64 | 111 | } |
65 | 112 |
|
@@ -125,6 +172,28 @@ private InferenceIndexInformationForField resolveIndicesForField(String fieldNam |
125 | 172 | return new InferenceIndexInformationForField(fieldName, inferenceIndicesMetadata, nonInferenceIndices); |
126 | 173 | } |
127 | 174 |
|
| 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 | + |
128 | 197 | protected QueryBuilder createSubQueryForIndices(Collection<String> indices, QueryBuilder queryBuilder) { |
129 | 198 | BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder(); |
130 | 199 | boolQueryBuilder.must(queryBuilder); |
|
0 commit comments