[Synonym] Return Empty RuleSet (#131032)
* Adding filter agg to include empty synonym sets * Adding featurespecification for synonyms * linting * Update docs/changelog/131032.yaml * update changelog * Adding synonym feature into module-info * sorted the expected response --------- Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
0b06d9f24d
commit
a12338aa27
|
@ -0,0 +1,5 @@
|
|||
pr: 131032
|
||||
summary: "Fix: `GET _synonyms` returns synonyms with empty rules"
|
||||
area: Relevance
|
||||
type: bug
|
||||
issues: []
|
|
@ -157,3 +157,33 @@ setup:
|
|||
|
||||
- match:
|
||||
count: 12
|
||||
|
||||
---
|
||||
"Return empty rule set":
|
||||
- requires:
|
||||
cluster_features: [ synonyms_set.get.return_empty_synonym_sets ]
|
||||
reason: "synonyms_set get api return empty synonym sets"
|
||||
|
||||
- do:
|
||||
synonyms.put_synonym:
|
||||
id: empty-synonyms
|
||||
body:
|
||||
synonyms_set: []
|
||||
|
||||
- do:
|
||||
synonyms.get_synonyms_sets: {}
|
||||
|
||||
- match:
|
||||
count: 4
|
||||
|
||||
- match:
|
||||
results:
|
||||
- synonyms_set: "empty-synonyms"
|
||||
count: 0
|
||||
- synonyms_set: "test-synonyms-1"
|
||||
count: 3
|
||||
- synonyms_set: "test-synonyms-2"
|
||||
count: 1
|
||||
- synonyms_set: "test-synonyms-3"
|
||||
count: 2
|
||||
|
||||
|
|
|
@ -429,6 +429,7 @@ module org.elasticsearch.server {
|
|||
org.elasticsearch.index.mapper.MapperFeatures,
|
||||
org.elasticsearch.index.IndexFeatures,
|
||||
org.elasticsearch.search.SearchFeatures,
|
||||
org.elasticsearch.synonyms.SynonymFeatures,
|
||||
org.elasticsearch.script.ScriptFeatures,
|
||||
org.elasticsearch.search.retriever.RetrieversFeatures,
|
||||
org.elasticsearch.action.admin.cluster.stats.ClusterStatsFeatures,
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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.synonyms;
|
||||
|
||||
import org.elasticsearch.features.FeatureSpecification;
|
||||
import org.elasticsearch.features.NodeFeature;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class SynonymFeatures implements FeatureSpecification {
|
||||
private static final NodeFeature RETURN_EMPTY_SYNONYM_SETS = new NodeFeature("synonyms_set.get.return_empty_synonym_sets");
|
||||
|
||||
@Override
|
||||
public Set<NodeFeature> getTestFeatures() {
|
||||
return Set.of(RETURN_EMPTY_SYNONYM_SETS);
|
||||
}
|
||||
}
|
|
@ -50,6 +50,9 @@ import org.elasticsearch.indices.IndexCreationException;
|
|||
import org.elasticsearch.indices.SystemIndexDescriptor;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
import org.elasticsearch.search.aggregations.BucketOrder;
|
||||
import org.elasticsearch.search.aggregations.bucket.filter.Filters;
|
||||
import org.elasticsearch.search.aggregations.bucket.filter.FiltersAggregationBuilder;
|
||||
import org.elasticsearch.search.aggregations.bucket.filter.FiltersAggregator;
|
||||
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
|
||||
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
|
@ -94,6 +97,8 @@ public class SynonymsManagementAPIService {
|
|||
private static final int MAX_SYNONYMS_SETS = 10_000;
|
||||
private static final String SYNONYM_RULE_ID_FIELD = SynonymRule.ID_FIELD.getPreferredName();
|
||||
private static final String SYNONYM_SETS_AGG_NAME = "synonym_sets_aggr";
|
||||
private static final String RULE_COUNT_AGG_NAME = "rule_count";
|
||||
private static final String RULE_COUNT_FILTER_KEY = "synonym_rules";
|
||||
private static final int SYNONYMS_INDEX_MAPPINGS_VERSION = 1;
|
||||
public static final int INDEX_SEARCHABLE_TIMEOUT_SECONDS = 30;
|
||||
private final int maxSynonymsSets;
|
||||
|
@ -185,15 +190,33 @@ public class SynonymsManagementAPIService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all synonym sets with their rule counts, including empty synonym sets.
|
||||
* @param from The index of the first synonym set to return
|
||||
* @param size The number of synonym sets to return
|
||||
* @param listener The listener to return the synonym sets to
|
||||
*/
|
||||
public void getSynonymsSets(int from, int size, ActionListener<PagedResult<SynonymSetSummary>> listener) {
|
||||
BoolQueryBuilder synonymSetQuery = QueryBuilders.boolQuery()
|
||||
.should(QueryBuilders.termQuery(OBJECT_TYPE_FIELD, SYNONYM_SET_OBJECT_TYPE))
|
||||
.should(QueryBuilders.termQuery(OBJECT_TYPE_FIELD, SYNONYM_RULE_OBJECT_TYPE))
|
||||
.minimumShouldMatch(1);
|
||||
|
||||
// Aggregation query to count only synonym rules (excluding synonym set objects)
|
||||
FiltersAggregationBuilder ruleCountAggregation = new FiltersAggregationBuilder(
|
||||
RULE_COUNT_AGG_NAME,
|
||||
new FiltersAggregator.KeyedFilter(RULE_COUNT_FILTER_KEY, QueryBuilders.termQuery(OBJECT_TYPE_FIELD, SYNONYM_RULE_OBJECT_TYPE))
|
||||
);
|
||||
|
||||
client.prepareSearch(SYNONYMS_ALIAS_NAME)
|
||||
.setSize(0)
|
||||
// Retrieves aggregated synonym rules for each synonym set, excluding the synonym set object type
|
||||
.setQuery(QueryBuilders.termQuery(OBJECT_TYPE_FIELD, SYNONYM_RULE_OBJECT_TYPE))
|
||||
.setQuery(synonymSetQuery)
|
||||
.addAggregation(
|
||||
new TermsAggregationBuilder(SYNONYM_SETS_AGG_NAME).field(SYNONYMS_SET_FIELD)
|
||||
.order(BucketOrder.key(true))
|
||||
.size(maxSynonymsSets)
|
||||
.subAggregation(ruleCountAggregation)
|
||||
)
|
||||
.setPreference(Preference.LOCAL.type())
|
||||
.execute(new ActionListener<>() {
|
||||
|
@ -201,11 +224,11 @@ public class SynonymsManagementAPIService {
|
|||
public void onResponse(SearchResponse searchResponse) {
|
||||
Terms termsAggregation = searchResponse.getAggregations().get(SYNONYM_SETS_AGG_NAME);
|
||||
List<? extends Terms.Bucket> buckets = termsAggregation.getBuckets();
|
||||
SynonymSetSummary[] synonymSetSummaries = buckets.stream()
|
||||
.skip(from)
|
||||
.limit(size)
|
||||
.map(bucket -> new SynonymSetSummary(bucket.getDocCount(), bucket.getKeyAsString()))
|
||||
.toArray(SynonymSetSummary[]::new);
|
||||
SynonymSetSummary[] synonymSetSummaries = buckets.stream().skip(from).limit(size).map(bucket -> {
|
||||
Filters ruleCountFilters = bucket.getAggregations().get(RULE_COUNT_AGG_NAME);
|
||||
Filters.Bucket ruleCountBucket = ruleCountFilters.getBucketByKey(RULE_COUNT_FILTER_KEY);
|
||||
return new SynonymSetSummary(ruleCountBucket.getDocCount(), bucket.getKeyAsString());
|
||||
}).toArray(SynonymSetSummary[]::new);
|
||||
|
||||
listener.onResponse(new PagedResult<>(buckets.size(), synonymSetSummaries));
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ org.elasticsearch.rest.action.admin.cluster.GetSnapshotsFeatures
|
|||
org.elasticsearch.index.IndexFeatures
|
||||
org.elasticsearch.index.mapper.MapperFeatures
|
||||
org.elasticsearch.search.SearchFeatures
|
||||
org.elasticsearch.synonyms.SynonymFeatures
|
||||
org.elasticsearch.search.retriever.RetrieversFeatures
|
||||
org.elasticsearch.script.ScriptFeatures
|
||||
org.elasticsearch.cluster.routing.RoutingFeatures
|
||||
|
|
Loading…
Reference in New Issue