MST
星途 面试题库

面试题:ElasticSearch基本读模型在复杂业务场景下的实践

假设你负责一个电商搜索系统,需要实现商品的多维度搜索,包括按品牌、价格区间、销量、评分等多个字段进行过滤和排序,并且要支持模糊搜索商品名称。请详细描述如何基于ElasticSearch的基本读模型来设计和实现这样的搜索功能,包括索引结构设计、查询逻辑实现以及可能遇到的问题和解决方案。
13.0万 热度难度
数据库ElasticSearch

知识考点

AI 面试

面试题答案

一键面试

索引结构设计

  1. 字段类型定义
    • 商品名称:使用 text 类型,并配置合适的分词器,如 ik_smart 用于中文模糊搜索,同时可以增加 keyword 子字段用于精确匹配。例如:
    "product_name": {
        "type": "text",
        "analyzer": "ik_smart",
        "fields": {
            "keyword": {
                "type": "keyword"
            }
        }
    }
    
    • 品牌:使用 keyword 类型,因为品牌通常不需要分词,用于精确过滤。
    "brand": {
        "type": "keyword"
    }
    
    • 价格:使用 floatinteger 类型(根据价格精度需求),用于价格区间过滤。
    "price": {
        "type": "float"
    }
    
    • 销量:使用 integer 类型,用于按销量排序。
    "sales": {
        "type": "integer"
    }
    
    • 评分:使用 float 类型,用于按评分排序。
    "rating": {
        "type": "float"
    }
    
  2. 索引设置:合理设置 number_of_shardsnumber_of_replicas,根据数据量和服务器资源来确定。例如,对于数据量较大的情况,可以设置多个分片来提高并行处理能力。
    {
        "settings": {
            "number_of_shards": 3,
            "number_of_replicas": 1
        }
    }
    

查询逻辑实现

  1. 模糊搜索商品名称:使用 match 查询。例如:
    {
        "query": {
            "match": {
                "product_name": "搜索关键词"
            }
        }
    }
    
  2. 按品牌过滤:使用 term 查询。例如:
    {
        "query": {
            "bool": {
                "filter": [
                    {
                        "term": {
                            "brand": "品牌名称"
                        }
                    }
                ]
            }
        }
    }
    
  3. 按价格区间过滤:使用 range 查询。例如,查询价格在100到200之间的商品:
    {
        "query": {
            "bool": {
                "filter": [
                    {
                        "range": {
                            "price": {
                                "gte": 100,
                                "lte": 200
                            }
                        }
                    }
                ]
            }
        }
    }
    
  4. 按销量排序:在查询中添加 sort 字段。例如,按销量降序排序:
    {
        "query": {
            "match_all": {}
        },
        "sort": [
            {
                "sales": {
                    "order": "desc"
                }
            }
        ]
    }
    
  5. 按评分排序:类似按销量排序,修改 sort 字段为评分字段。例如,按评分降序排序:
    {
        "query": {
            "match_all": {}
        },
        "sort": [
            {
                "rating": {
                    "order": "desc"
                }
            }
        ]
    }
    
  6. 组合查询:使用 bool 查询将上述各种查询条件组合起来。例如,模糊搜索商品名称,同时按品牌过滤和按销量排序:
    {
        "query": {
            "bool": {
                "must": [
                    {
                        "match": {
                            "product_name": "搜索关键词"
                        }
                    }
                ],
                "filter": [
                    {
                        "term": {
                            "brand": "品牌名称"
                        }
                    }
                ]
            }
        },
        "sort": [
            {
                "sales": {
                    "order": "desc"
                }
            }
        ]
    }
    

可能遇到的问题和解决方案

  1. 性能问题
    • 问题:数据量增大后,查询性能下降。
    • 解决方案
      • 合理设置索引分片和副本,确保负载均衡。
      • 使用缓存,如 Redis,缓存热门查询结果。
      • 对经常查询的字段创建合适的索引,例如对品牌、价格等过滤字段。
  2. 分词问题
    • 问题:模糊搜索结果不准确,分词不合理。
    • 解决方案
      • 选择合适的分词器,如对于中文可以使用 ik_smartik_max_word,并根据业务需求调整分词策略。
      • 对分词结果进行测试和优化,通过 _analyze API 查看分词效果并进行调整。
  3. 数据一致性问题
    • 问题:数据更新后,搜索结果不能及时反映最新数据。
    • 解决方案
      • 了解 ElasticSearch 的刷新机制,合理设置刷新间隔。可以手动调用 _refresh API 使数据尽快可见,但频繁刷新会影响性能。
      • 使用异步更新机制,在数据更新后,通过消息队列等方式异步通知 ElasticSearch 进行数据更新,确保数据一致性的同时减少对业务系统的影响。