ElasticSearch复习指南:从零搭建一个商品搜索案例

前言:为什么我们需要ElasticSearch?

想象一下,你正在开发一个电商网站,商品数量达到百万级别。用户需要能够快速搜索商品,并且希望支持模糊匹配、按价格筛选、按分类过滤等功能。

如果使用传统的数据库(如MySQL)来实现,你可能会写出这样的查询:

sql 复制代码
SELECT * FROM products 
WHERE name LIKE '%手机%' 
AND price BETWEEN 1000 AND 5000 
AND category_id = 1
ORDER BY create_time DESC
LIMIT 20 OFFSET 0;

随着数据量增加,这种查询会变得越来越慢,而且无法很好地支持模糊搜索和相关度排序。这就是ElasticSearch的用武之地。

一、ElasticSearch核心概念快速回顾

1.1 倒排索引:为什么ES这么快?

传统数据库使用"正排索引":文档→关键词

复制代码
文档1:我爱学习ElasticSearch
文档2:ElasticSearch真强大

而ElasticSearch使用"倒排索引":关键词→文档

复制代码
我: [文档1]
爱: [文档1]
学习: [文档1]
ElasticSearch: [文档1, 文档2]
真: [文档2]
强大: [文档2]

这样搜索"ElasticSearch"时,直接就能找到文档1和文档2,无需扫描所有文档。

1.2 基本概念对照表

ElasticSearch术语 传统数据库类比 说明
Index(索引) Database(数据库) 数据容器
Type(类型) Table(表) ES7+已废弃
Document(文档) Row(行) 基本数据单位
Field(字段) Column(列) 数据字段
Mapping(映射) Schema(模式) 数据结构定义

二、实战案例:搭建商品搜索系统

让我们通过一个真实案例来复习ElasticSearch的使用。

2.1 环境准备

首先使用Docker启动ElasticSearch和Kibana:

复制代码
# 启动ElasticSearch
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.17.0

# 启动Kibana(Web管理界面)
docker run -d --name kibana --link elasticsearch:elasticsearch -p 5601:5601 kibana:7.17.0

2.2 创建商品索引

假设我们的商品有以下字段:

  • id:商品ID

  • name:商品名称

  • price:价格

  • category:分类

  • description:描述

  • tags:标签数组

    PUT /products
    {
    "mappings": {
    "properties": {
    "id": { "type": "integer" },
    "name": {
    "type": "text",
    "analyzer": "ik_max_word", // 使用中文分词器
    "search_analyzer": "ik_smart"
    },
    "price": { "type": "float" },
    "category": { "type": "keyword" },
    "description": {
    "type": "text",
    "analyzer": "ik_max_word"
    },
    "tags": { "type": "keyword" },
    "created_at": { "type": "date" }
    }
    }
    }

2.3 插入测试数据

复制代码
POST /products/_bulk
{"index":{"_id":1}}
{"id":1,"name":"Apple iPhone 13","price":5999,"category":"手机","description":"新一代iPhone,A15芯片,超视网膜XDR显示屏","tags":["苹果","智能手机","5G"],"created_at":"2022-01-01"}
{"index":{"_id":2}}
{"id":2,"name":"华为Mate 50","price":5499,"category":"手机","description":"华为旗舰手机,鸿蒙系统,超强拍照","tags":["华为","智能手机","5G"],"created_at":"2022-02-01"}
{"index":{"_id":3}}
{"id":3,"name":"小米手环7","price":249,"category":"智能穿戴","description":"1.62英寸AMOLED屏,120种运动模式","tags":["小米","智能手环","健康监测"],"created_at":"2022-03-01"}

2.4 实现复杂搜索功能

​案例1:基本搜索​​ - 查找商品名称或描述中包含"手机"的商品

复制代码
GET /products/_search
{
  "query": {
    "multi_match": {
      "query": "手机",
      "fields": ["name", "description"]
    }
  }
}

​案例2:多条件过滤​​ - 搜索手机分类中,价格在5000-6000之间的商品

复制代码
GET /products/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "category": "手机" } }
      ],
      "filter": [
        { "range": { "price": { "gte": 5000, "lte": 6000 } } }
      ]
    }
  }
}

​案例3:模糊搜索与评分​​ - 搜索"华为"(用户输入错误)

复制代码
GET /products/_search
{
  "query": {
    "fuzzy": {
      "name": {
        "value": "华为",
        "fuzziness": "AUTO"
      }
    }
  }
}

​案例4:聚合分析​​ - 统计每个分类的商品数量和平均价格

复制代码
GET /products/_search
{
  "size": 0,
  "aggs": {
    "categories": {
      "terms": {
        "field": "category"
      },
      "aggs": {
        "avg_price": {
          "avg": {
            "field": "price"
          }
        }
      }
    }
  }
}

三、性能优化技巧

3.1 索引设计优化

  1. ​合理使用字段类型​​:

    • 精确匹配用keyword
    • 文本搜索用text+适当的分词器
  2. ​索引分片策略​​:

    复制代码
    PUT /products
    {
      "settings": {
        "number_of_shards": 3,    // 主分片数,一旦设置不能修改
        "number_of_replicas": 1   // 副本分片数,可随时调整
      }
    }

3.2 查询优化

  1. ​避免深度分页​ :使用search_after代替from/size

  2. ​使用过滤器上下文​:filter不计算评分,性能更好

  3. ​合理使用索引别名​:实现零停机重建索引

    // 1. 创建新索引
    PUT /products_new

    // 2. 将数据从旧索引迁移到新索引
    POST _reindex
    {
    "source": { "index": "products" },
    "dest": { "index": "products_new" }
    }

    // 3. 原子操作切换别名
    POST _aliases
    {
    "actions": [
    { "remove": { "index": "products", "alias": "products_alias" } },
    { "add": { "index": "products_new", "alias": "products_alias" } }
    ]
    }

四、常见问题与解决方案

4.1 数据同步问题:如何保证数据库与ES数据一致?

推荐使用两种方案:

  1. ​双写模式​​:应用代码中同时写入数据库和ES

    • 优点:简单直接
    • 缺点:可能存在数据不一致
  2. ​日志订阅模式​​:通过CDC工具(如Canal、Debezium)捕获数据库变更

    • 优点:解耦,保证最终一致性
    • 缺点:架构复杂

4.2 中文分词问题

ES默认的中文分词效果不好,推荐使用IK分词器:

复制代码
PUT /products
{
  "settings": {
    "analysis": {
      "analyzer": {
        "ik_smart_custom": {
          "type": "custom",
          "tokenizer": "ik_smart"
        }
      }
    }
  }
}

五、总结

通过这个商品搜索案例,我们复习了ElasticSearch的核心概念和实际应用:

  1. ​倒排索引​是ES高性能搜索的基石
  2. ​合理的Mapping设计​对搜索性能和准确性至关重要
  3. ​复合查询​可以满足复杂的业务需求
  4. ​聚合分析​提供了强大的数据分析能力
  5. ​性能优化​需要从索引设计和查询两方面入手
相关推荐
2301_818411558 小时前
rpm软件包管理以及yum,apt的前端软件包管理器
linux·运维·服务器
源文雨8 小时前
MacOS 下 Warp ping 局域网设备报错 ping: sendto: No route to host 的解决方法
运维·网络协议·安全·macos·网络安全·ping
葵花日记10 小时前
LINUX——进度条
linux·运维·服务器
hmcjn(小何同学)11 小时前
轻松Linux-10.进程信号
linux·运维·服务器
不爱学习的老登11 小时前
从零开始搭建私有服务器并部署网站
运维·服务器
深思慎考11 小时前
【新版】Elasticsearch 8.15.2 完整安装流程(Linux国内镜像提速版)
java·linux·c++·elasticsearch·jenkins·框架
mxpan11 小时前
VirtualBox中ubuntu1804虚拟机共享文件夹设置
linux·运维·服务器
别多香了11 小时前
项目实战:ecshop
linux·运维·服务器
de之梦-御风13 小时前
【Linux】 MediaMTX测试是否运行
linux·运维·服务器
早睡冠军候选人13 小时前
K8s学习----StorageClass:实现存储资源的动态管理
运维·学习·云原生·容器·kubernetes