From 6acc99c7cff056751cebd5e9ff668933ba4961c3 Mon Sep 17 00:00:00 2001 From: "pikachu1995@126.com" Date: Tue, 26 Aug 2025 19:33:15 +0800 Subject: [PATCH] =?UTF-8?q?perf(es):=20=E4=BC=98=E5=8C=96=E5=93=81?= =?UTF-8?q?=E7=89=8C=E8=81=9A=E5=90=88=E6=9F=A5=E8=AF=A2=E5=92=8C=E7=BD=91?= =?UTF-8?q?=E7=BB=9C=E8=BF=9E=E6=8E=A5=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -增加 connectionRequestTimeout 配置,设置为 1000 毫秒 -调整 maxConnPerRoute 为 50,maxConnTotal为 200 -限制 terms 聚合 size,防止内存压力 - 优化品牌聚合查询逻辑,提高查询效率和准确性 --- framework/pom.xml | 9 -- .../config/ElasticsearchConfig.java | 6 +- .../serviceimpl/EsGoodsSearchServiceImpl.java | 83 ++++++++++++------- 3 files changed, 58 insertions(+), 40 deletions(-) diff --git a/framework/pom.xml b/framework/pom.xml index 2b359058b..fb68bc344 100644 --- a/framework/pom.xml +++ b/framework/pom.xml @@ -15,15 +15,6 @@ jar - - com.qiniu - qiniu-java-sdk - - - com.qiniu - qiniu-java-sdk - 7.4.0 - org.springframework.boot spring-boot-properties-migrator diff --git a/framework/src/main/java/cn/lili/elasticsearch/config/ElasticsearchConfig.java b/framework/src/main/java/cn/lili/elasticsearch/config/ElasticsearchConfig.java index 6f384fd9b..2ddcd8680 100644 --- a/framework/src/main/java/cn/lili/elasticsearch/config/ElasticsearchConfig.java +++ b/framework/src/main/java/cn/lili/elasticsearch/config/ElasticsearchConfig.java @@ -66,14 +66,16 @@ public class ElasticsearchConfig extends AbstractElasticsearchConfiguration { .setRequestConfigCallback(requestConfigBuilder -> requestConfigBuilder .setConnectTimeout(1000) - .setSocketTimeout(12 * 1000)); + .setSocketTimeout(12 * 1000) + .setConnectionRequestTimeout(1000)); } private HttpAsyncClientBuilder configureHttpClientBuilder(HttpAsyncClientBuilder httpClientBuilder, CredentialsProvider credentialsProvider) { httpClientBuilder .setKeepAliveStrategy(getConnectionKeepAliveStrategy()) - .setMaxConnPerRoute(10) + .setMaxConnPerRoute(50) + .setMaxConnTotal(200) .setDefaultIOReactorConfig( IOReactorConfig .custom() diff --git a/framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsSearchServiceImpl.java b/framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsSearchServiceImpl.java index f752e4c5a..de7cf361e 100644 --- a/framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsSearchServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsSearchServiceImpl.java @@ -68,6 +68,8 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService { private static final String ATTR_BRAND_URL = "brandUrlAgg"; private static final String ATTR_NAME_KEY = "nameList"; private static final String ATTR_VALUE_KEY = "valueList"; + // 限制 terms 聚合 size,防止内存压力 + private static final int MAX_AGG_SIZE = 200; /** * ES */ @@ -122,23 +124,24 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService { if (!restTemplate.indexOps(EsGoodsIndex.class).exists()) { return null; } - NativeSearchQueryBuilder builder = createSearchQueryBuilder(goodsSearch, null); //分类 - AggregationBuilder categoryNameBuilder = AggregationBuilders.terms("categoryNameAgg").field("categoryNamePath.keyword"); - builder.addAggregation(AggregationBuilders.terms("categoryAgg").field("categoryPath").subAggregation(categoryNameBuilder)); + AggregationBuilder categoryNameBuilder = AggregationBuilders.terms("categoryNameAgg").field("categoryNamePath.keyword").size(MAX_AGG_SIZE); + builder.addAggregation(AggregationBuilders.terms("categoryAgg").field("categoryPath").size(MAX_AGG_SIZE).subAggregation(categoryNameBuilder)); //品牌 - AggregationBuilder brandNameBuilder = AggregationBuilders.terms(ATTR_BRAND_NAME).field("brandName.keyword"); - builder.addAggregation(AggregationBuilders.terms("brandIdNameAgg").field(ATTR_BRAND_ID).size(Integer.MAX_VALUE).subAggregation(brandNameBuilder)); + AggregationBuilder brandNameBuilder = AggregationBuilders.terms(ATTR_BRAND_NAME).field("brandName.keyword").size(1); + builder.addAggregation(AggregationBuilders.terms("brandIdNameAgg").field(ATTR_BRAND_ID).size(MAX_AGG_SIZE).subAggregation(brandNameBuilder)); - AggregationBuilder brandUrlBuilder = AggregationBuilders.terms(ATTR_BRAND_URL).field("brandUrl.keyword"); - builder.addAggregation(AggregationBuilders.terms("brandIdUrlAgg").field(ATTR_BRAND_ID).size(Integer.MAX_VALUE).subAggregation(brandUrlBuilder)); + AggregationBuilder brandUrlBuilder = AggregationBuilders.terms(ATTR_BRAND_URL).field("brandUrl.keyword").size(1); + builder.addAggregation(AggregationBuilders.terms("brandIdUrlAgg").field(ATTR_BRAND_ID).size(MAX_AGG_SIZE).subAggregation(brandUrlBuilder)); //参数 - AggregationBuilder valuesBuilder = AggregationBuilders.terms("valueAgg").field(ATTR_VALUE); + AggregationBuilder valuesBuilder = AggregationBuilders.terms("valueAgg").field(ATTR_VALUE).size(MAX_AGG_SIZE); AggregationBuilder sortBuilder = AggregationBuilders.sum("sortAgg").field(ATTR_SORT); - AggregationBuilder paramsNameBuilder = AggregationBuilders.terms("nameAgg").field(ATTR_NAME).subAggregation(sortBuilder).order(BucketOrder.aggregation("sortAgg", false)).subAggregation(valuesBuilder); + AggregationBuilder paramsNameBuilder = AggregationBuilders.terms("nameAgg").field(ATTR_NAME).size(MAX_AGG_SIZE) + .subAggregation(sortBuilder).order(BucketOrder.aggregation("sortAgg", false)).subAggregation(valuesBuilder); builder.addAggregation(AggregationBuilders.nested("attrAgg", ATTR_PATH).subAggregation(paramsNameBuilder)); + NativeSearchQuery searchQuery = builder.build(); searchQuery.setMaxResults(0); SearchHits search = restTemplate.search(searchQuery, EsGoodsIndex.class); @@ -227,35 +230,57 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService { */ private List convertBrandOptions(EsGoodsSearchDTO goodsSearch, List brandBuckets, List brandUrlBuckets) { List brandOptions = new ArrayList<>(); - for (int i = 0; i < brandBuckets.size(); i++) { - String brandId = brandBuckets.get(i).getKey().toString(); - //当商品品牌id为0时,代表商品没有选择品牌,所以过滤掉品牌选择器 - //当品牌id为空并且 - if (brandId.equals("0") || - (CharSequenceUtil.isNotEmpty(goodsSearch.getBrandId()) - && Arrays.asList(goodsSearch.getBrandId().split("@")).contains(brandId))) { + // 以 brandId 为 key 构建 URL 桶索引,避免按下标对齐产生越界/错位 + Map brandUrlBucketMap = new HashMap<>(); + if (brandUrlBuckets != null) { + for (Terms.Bucket urlBucket : brandUrlBuckets) { + if (urlBucket != null && urlBucket.getKey() != null) { + brandUrlBucketMap.put(urlBucket.getKey().toString(), urlBucket); + } + } + } + + Set selectedBrandIds = new HashSet<>(); + if (CharSequenceUtil.isNotEmpty(goodsSearch.getBrandId())) { + selectedBrandIds.addAll(Arrays.asList(goodsSearch.getBrandId().split("@"))); + } + + for (Terms.Bucket bucket : brandBuckets) { + if (bucket == null || bucket.getKey() == null) { + continue; + } + String brandId = bucket.getKey().toString(); + // 排除无品牌或已选择品牌 + if ("0".equals(brandId) || (!selectedBrandIds.isEmpty() && selectedBrandIds.contains(brandId))) { continue; } + // 品牌名 String brandName = ""; - if (brandBuckets.get(i).getAggregations() != null && brandBuckets.get(i).getAggregations().get(ATTR_BRAND_NAME) != null) { - ParsedStringTerms aggregation = brandBuckets.get(i).getAggregations().get(ATTR_BRAND_NAME); - brandName = this.getAggregationsBrandOptions(aggregation); - if (StringUtils.isEmpty(brandName)) { - continue; + Aggregations nameAggs = bucket.getAggregations(); + if (nameAggs != null) { + Aggregation nameAgg = nameAggs.get(ATTR_BRAND_NAME); + if (nameAgg instanceof ParsedStringTerms) { + brandName = this.getAggregationsBrandOptions((ParsedStringTerms) nameAgg); } } + if (StringUtils.isEmpty(brandName)) { + continue; + } + // 品牌 URL String brandUrl = ""; - if (brandUrlBuckets != null && !brandUrlBuckets.isEmpty() && - brandUrlBuckets.get(i).getAggregations() != null && - brandUrlBuckets.get(i).getAggregations().get(ATTR_BRAND_URL) != null) { - ParsedStringTerms aggregation = brandUrlBuckets.get(i).getAggregations().get(ATTR_BRAND_URL); - brandUrl = this.getAggregationsBrandOptions(aggregation); - if (StringUtils.isEmpty(brandUrl)) { - continue; + Terms.Bucket urlBucket = brandUrlBucketMap.get(brandId); + if (urlBucket != null && urlBucket.getAggregations() != null) { + Aggregation urlAgg = urlBucket.getAggregations().get(ATTR_BRAND_URL); + if (urlAgg instanceof ParsedStringTerms) { + brandUrl = this.getAggregationsBrandOptions((ParsedStringTerms) urlAgg); } } + if (StringUtils.isEmpty(brandUrl)) { + continue; + } + SelectorOptions so = new SelectorOptions(); so.setName(brandName); so.setValue(brandId); @@ -475,7 +500,7 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService { //品牌判定 if (CharSequenceUtil.isNotEmpty(searchDTO.getBrandId())) { String[] brands = searchDTO.getBrandId().split("@"); - filterBuilder.must(QueryBuilders.termsQuery(ATTR_BRAND_ID, brands)); + filterBuilder.filter(QueryBuilders.termsQuery(ATTR_BRAND_ID, brands)); } if (searchDTO.getRecommend() != null) { filterBuilder.filter(QueryBuilders.termQuery("recommend", searchDTO.getRecommend()));