ElasticSearch业务场景与面试题

以下是几个常见的 Elasticsearch 业务场景解决方案及面试题解析(含 Java 示例):


一、业务场景解决方案


场景 1:商品搜索与过滤

需求:电商平台需要支持多条件搜索(关键词、价格区间、分类、品牌)并按相关性排序。

解决方案

  1. Bool Query :组合 must(必须匹配)、should(加分项)、filter(无评分过滤)。
  2. Keyword 字段 :分类/品牌等精确匹配字段使用 keyword 类型。
  3. 范围查询 :价格区间使用 range 查询。
  4. 相关性排序:使用 TF-IDF 或 BM25 算法(ES 默认)。
java 复制代码
// 使用 RestHighLevelClient(旧版)或 Java Client(新版)
SearchRequest request = new SearchRequest("products");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
    .must(QueryBuilders.matchQuery("name", "手机")) // 关键词匹配
    .filter(QueryBuilders.rangeQuery("price").gte(1000).lte(5000)) // 价格过滤
    .filter(QueryBuilders.termQuery("category", "electronics")) // 分类精确匹配
    .should(QueryBuilders.matchQuery("brand", "Apple").boost(2.0f)); // 品牌加分

sourceBuilder.query(boolQuery)
    .sort(SortBuilders.scoreSort()) // 按相关性排序
    .from(0).size(10); // 分页

request.source(sourceBuilder);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);

场景 2:日志分析与聚合

需求:分析系统日志中不同错误级别的出现次数。

解决方案

  1. Date Histogram:按时间区间聚合。
  2. Terms Aggregation:按错误级别分组统计。
  3. 索引设计 :使用 @timestamp 字段记录日志时间。
java 复制代码
SearchRequest request = new SearchRequest("logs");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

// 按错误级别聚合
TermsAggregationBuilder termsAgg = AggregationBuilders.terms("error_levels").field("level");
// 子聚合:按小时统计
DateHistogramAggregationBuilder dateHistogram = AggregationBuilders.dateHistogram("per_hour")
    .field("@timestamp").calendarInterval(DateHistogramInterval.HOUR);

termsAgg.subAggregation(dateHistogram);
sourceBuilder.aggregation(termsAgg);

request.source(sourceBuilder);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);

// 解析聚合结果
Terms terms = response.getAggregations().get("error_levels");
for (Terms.Bucket bucket : terms.getBuckets()) {
    String level = bucket.getKeyAsString();
    DateHistogram dateHistogramAgg = bucket.getAggregations().get("per_hour");
    for (DateHistogram.Bucket hourBucket : dateHistogramAgg.getBuckets()) {
        System.out.println(level + " - " + hourBucket.getKeyAsString() + ": " + hourBucket.getDocCount());
    }
}

场景 3:搜索自动补全

需求:实现类似 Google 的搜索框自动补全功能。

解决方案

  1. Completion Suggester:专为自动补全设计的字段类型。
  2. N-gram 分词:支持部分匹配(如 "el" 匹配 "elasticsearch")。
java 复制代码
// 创建索引时定义补全字段
CreateIndexRequest request = new CreateIndexRequest("suggestions");
request.mapping(
    "{\n" +
    "  \"properties\": {\n" +
    "    \"suggest\": {\n" +
    "      \"type\": \"completion\"\n" +
    "    }\n" +
    "  }\n" +
    "}",
    XContentType.JSON
);
client.indices().create(request, RequestOptions.DEFAULT);

// 查询时使用 Suggest
SuggestBuilder suggestBuilder = new SuggestBuilder()
    .addSuggestion("my_suggestion",
        new CompletionSuggestionBuilder("suggest").prefix("el").size(5));

SearchSourceBuilder sourceBuilder = new SearchSourceBuilder().suggest(suggestBuilder);
SearchRequest searchRequest = new SearchRequest("suggestions").source(sourceBuilder);
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);

// 解析补全结果
CompletionSuggestion suggestion = response.getSuggest().getSuggestion("my_suggestion");
for (CompletionSuggestion.Entry.Option option : suggestion.getOptions()) {
    System.out.println(option.getText().string());
}

二、高频面试题


问题 1:Elasticsearch 如何保证数据一致性?
  • :ES 是近实时(NRT)系统,默认每秒刷新(refresh)一次。写入数据后需等待刷新或手动调用 refresh 才能搜索到。通过 wait_for 参数可强制等待变更可见:

    java 复制代码
    IndexRequest request = new IndexRequest("index")
        .source("field", "value")
        .setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);

问题 2:如何处理深度分页的性能问题?
  • :避免使用 from + size(如 from=10000),改用 search_after

    java 复制代码
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder()
        .sort(SortBuilders.fieldSort("_id")) // 必须包含唯一排序字段
        .size(10);
    
    // 第一次查询
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    SearchHit[] hits = response.getHits().getHits();
    
    // 后续分页使用 search_after
    sourceBuilder.searchAfter(hits[hits.length - 1].getSortValues());

问题 3:如何同步 MySQL 数据到 Elasticsearch?
  • 方案
    1. Logstash JDBC Input:定时拉取 MySQL 数据。
    2. Binlog 监听:使用 Canal 或 Debezium 捕获 MySQL 变更,通过 Kafka 同步到 ES。
    3. 双写:应用层直接写入 MySQL 和 ES(需处理事务一致性)。

问题 4:如何优化 Elasticsearch 集群性能?
    • 硬件:使用 SSD、增加内存。
    • 索引设计 :合理设置分片数(建议单个分片 10-50GB)、关闭不需要的字段 norms
    • 查询优化 :避免通配符查询、使用 filter 替代 query 避免评分。
    • 冷热分离:将历史数据迁移到冷节点。

三、陷阱与注意事项

  1. 分片数不可变:创建索引时需预先规划分片数量。
  2. 脑裂问题 :通过 discovery.zen.minimum_master_nodes(旧版)或 cluster.initial_master_nodes(新版)配置避免。
  3. 映射爆炸:限制动态映射,避免过多字段导致内存问题。

以上内容覆盖了常见场景和面试考点,结合 Java 代码可快速实现功能验证。

相关推荐
feilieren4 小时前
Docker 安装 Elasticsearch 9
运维·elasticsearch·docker·es
Java烘焙师7 小时前
架构师必备:业务扩展模式选型
mysql·elasticsearch·架构·hbase·多维度查询
G皮T20 小时前
【Elasticsearch】深度分页及其替代方案
大数据·elasticsearch·搜索引擎·scroll·检索·深度分页·search_after
G皮T1 天前
【Elasticsearch】检索排序 & 分页
大数据·elasticsearch·搜索引擎·排序·分页·检索·深度分页
飞询1 天前
Docker 安装 Elasticsearch 9
elasticsearch·docker
G皮T1 天前
【Elasticsearch】检索高亮
大数据·elasticsearch·搜索引擎·全文检索·kibana·检索·高亮
Leon.ENV1 天前
meilisearch-轻量级搜索引擎
搜索引擎
大只鹅2 天前
解决 Spring Boot 对 Elasticsearch 字段没有小驼峰映射的问题
spring boot·后端·elasticsearch
HGW6892 天前
基于 Elasticsearch 实现地图点聚合
java·elasticsearch·高德地图
小袁拒绝摆烂2 天前
ElasticSearch快速入门-1
大数据·elasticsearch·搜索引擎