ES快速入门

背景

解决了什么问题:解决海量数据下的快速检索、模糊查询、分词搜索、聚合统计问题。

如何解决的:分词+倒排索引

为什么这么解决:倒排索引是全文检索最高效的结构,比数据库 like / 正则快几个数量级

对比mysql

文档是可以搜索的最小单元

ES + kibana

这里是docker容器启动的。

dart 复制代码
version: '3.8'  # Compose文件版本(与Docker版本兼容即可)

services:
  # 1. ZooKeeper(Kafka依赖,用于集群协调)
  zookeeper:
    image: confluentinc/cp-zookeeper:7.3.0  # 稳定版本镜像
    container_name: zookeeper
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181  # 容器内端口
      ZOOKEEPER_TICK_TIME: 2000    # 心跳间隔
    ports:
      - "2181:2181"  # 宿主机端口:容器内端口(IDEA通过宿主机端口访问)
    restart: always  # 容器异常时自动重启
    networks:
      - app-network  # 加入自定义网络

  # 2. Kafka(消息队列)
  kafka:
    image: confluentinc/cp-kafka:7.3.0
    container_name: kafka
    depends_on:
      - zookeeper  # 依赖ZooKeeper,启动顺序:先启动ZooKeeper
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181  # 连接容器内的ZooKeeper(用容器名作为 hostname)
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9093,PLAINTEXT_HOST://localhost:9092
      # 关键配置:PLAINTEXT_HOST映射到宿主机localhost,Java客户端通过 localhost:9092 连接
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
    ports:
      - "9092:9092"  # Kafka宿主机访问端口
    restart: always
    networks:
      - app-network  # 加入自定义网络

  # 3. Elasticsearch(搜索引擎)
  elasticsearch:
    image: elasticsearch:7.17.0  # 稳定版本(避免用8.x,默认开启HTTPS,新手易踩坑)
    container_name: elasticsearch
    environment:
      - discovery.type=single-node  # 单节点模式(开发环境用)
      - ES_JAVA_OPTS=-Xms512m -Xmx512m  # 限制JVM内存(避免占满宿主机内存)
      - xpack.security.enabled=false  # 关闭安全验证(开发环境简化配置)
      - http.cors.enabled=true  # 开启跨域(elasticvue需要)
      - http.cors.allow-origin=*  # 允许所有来源跨域(开发环境)
    ports:
      - "9200:9200"  # ES HTTP访问端口(IDEA/Java客户端连接用)
      - "9300:9300"  # ES集群通信端口(单节点可忽略)
    volumes:
      - es-data:/usr/share/elasticsearch/data  # 数据持久化(容器删除后数据不丢失)
    restart: always
    networks:
      - app-network  # 加入自定义网络

  # 4. Redis 服务(开发环境配置,带密码+数据持久化)
  redis:
    image: redis:6.2-alpine  # 轻量稳定版本(Alpine镜像体积更小)
    container_name: redis
    environment:
      - REDIS_PASSWORD=123456  # 设置Redis密码(开发环境简化,可自定义)
      - REDIS_MAXMEMORY=512mb  # 限制最大内存(避免占满宿主机)
      - REDIS_MAXMEMORY_POLICY=allkeys-lru  # 内存满时淘汰策略(删除最近最少使用的key)
    command: redis-server --requirepass 123456 --appendonly yes  # 开启AOF持久化(数据不丢失)
    ports:
      - "6379:6379"  # 宿主机端口映射(Java项目通过 localhost:6379 访问)
    volumes:
      - redis-data:/data  # 数据持久化目录(容器删除后数据保留)
    restart: always  # 异常自动重启
    networks:
      - app-network  # 加入自定义网络

  # 5. Kibana(Elasticsearch可视化工具)
  kibana:
    image: kibana:7.17.0  # 版本必须和Elasticsearch完全一致(7.17.0)
    container_name: kibana
    depends_on:
      - elasticsearch  # 依赖ES,确保ES先启动
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200  # 连接容器内的ES(用容器名访问)
      - XPACK_SECURITY_ENABLED=false  # 关闭安全验证(和ES保持一致)
      - SERVER_PORT=5601  # Kibana服务端口
    ports:
      - "5601:5601"  # 宿主机访问端口(浏览器打开 http://localhost:5601 即可使用)
    restart: always
    networks:
      - app-network  # 加入自定义网络,和ES/其他服务互通

# 数据卷声明
volumes:
  es-data:
  redis-data:  # 声明Redis数据卷

# 自定义网络(确保所有服务互通)
networks:
  app-network:
    driver: bridge  # 桥接网络,默认驱动,所有服务(包括Kibana)都加入此网络

增加:

dart 复制代码
# 创建索引(指定字段类型)
PUT /product_index
{
  "mappings": {
    "properties": {
      "id": { "type": "keyword" },        # 商品ID:精确匹配,不分词
      "name": { "type": "text",           # 商品名称:支持全文检索
        "fields": {
          "keyword": { "type": "keyword" } # 子字段:用于精确匹配/聚合。也就是name字段既可以分词匹配,又可以精确匹配
        }
      },
      "price": { "type": "double" },      # 价格:数值类型
      "category": { "type": "keyword" },  # 分类:枚举值,精确匹配
      "create_time": { "type": "date" }   # 创建时间:日期类型
    }
  }
}

# 验证索引是否创建成功
GET /product_index

# 方式1:指定ID新增(PUT),ID不存在则创建,存在则覆盖
PUT /product_index/_doc/1001
{
  "id": "P1001",
  "name": "小米14 5G手机",
  "price": 3999.0,
  "category": "手机",
  "create_time": "2026-02-24T10:00:00"
}

# 方式2:自动生成ID新增(POST),适合无固定ID的场景
POST /product_index/_doc
{
  "id": "P1002",
  "name": "华为Mate60 Pro",
  "price": 6999.0,
  "category": "手机",
  "create_time": "2026-02-24T10:05:00"
}

# 验证新增结果(查询指定ID文档)
GET /product_index/_doc/1001

# 查询所有的数据
GET /product_index/_search
{
  "query": { "match_all": {} }
}

删除:

dart 复制代码
# 方式1:按ID删除单个文档
DELETE /product_index/_doc/1001

# 方式2:按条件批量删除(需先安装Delete By Query插件,ES 7.x+默认支持)
POST /product_index/_delete_by_query
{
  "query": {
    "term": { "category": "手机" } 
  }
}

改变:

dart 复制代码
POST /product_index/_update/1001
{
  "doc": {
    "price": 3899.0,          
    "category": "智能手机"  
  }
}

# 方式2:全量覆盖(PUT),需传入所有字段,否则未传字段会丢失
PUT /product_index/_doc/1001
{
  "id": "P1001" 
}

查询:

dart 复制代码
# 场景1:按ID精确查询
GET /product_index/_doc/1001

# 场景2:全文检索(匹配商品名称) match是分词匹配,term是精确匹配
GET /product_index/_search
{
  "query": {
    "match": {
      "name": "小米手机"  # 分词后匹配,会命中"小米14 5G手机"
    }
  }
}

# 场景3:精确匹配+过滤+排序+分页
GET /product_index/_search
{
  "query": {
    "bool": {
      "must": [ { "term": { "category": "手机" } } ], # 精确匹配分类
      "filter": [ { "range": { "price": { "lte": 5000 } } } ] # 过滤价格≤5000
    }
  },
  "sort": [ { "price": { "order": "desc" } } ], # 按价格降序
  "from": 0, "size": 10,                        # 分页:第1页,每页10条
  "_source": [ "id", "name", "price" ]          # 只返回指定字段
}

# 场景4:查询所有文档(慎用,大数据量会性能问题)
GET /product_index/_search
{
  "query": { "match_all": {} }
}

Java api

文档对象:

dart 复制代码
package com.xop.business.middleware.elasticsearch.demo2;

import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

import java.time.LocalDateTime;

/**
 * 商品文档类
 * 对应 Elasticsearch 的 product_index 索引(id字段与索引Mapping完全对齐)
 */
@Document(indexName = "product_index") // 对应ES的商品索引名
@Getter
@Setter
public class SampleDocument {

    /**
     * 文档ID(对应ES的_id,Spring Data ES 专用)
     */
    @Id
    @Transient
    private String docId;

    /**
     * 商品ID(业务唯一标识,对应ES的id字段,keyword类型)
     */
    @Field(type = FieldType.Keyword, name = "id") // 显式指定对应ES的id字段
    private String id;

    /**
     * 商品名称(支持中文分词,同时保留keyword子字段用于精确匹配/聚合)
     */
    /**
     * 商品名称(支持中文分词,同时保留keyword子字段用于精确匹配/聚合)
     */
    /**
     * 商品名称(支持中文IK分词,同时保留keyword子字段用于精确匹配/聚合)
     */
    @Field(
            name = "name", // 显式指定对应ES的name字段(与AliasFor的value等效,二选一即可)
            type = FieldType.Text,
            analyzer = "ik_max_word" // 中文IK分词器(最大粒度拆分)
    )
    private String name;

    /**
     * 商品价格(数值类型,对应ES的price字段)
     */
    @Field(type = FieldType.Double, name = "price")
    private Double price;

    /**
     * 商品分类(枚举值,对应ES的category字段)
     */
    @Field(type = FieldType.Keyword, name = "category")
    private String category;

    /**
     * 创建时间(日期类型,对应ES的create_time字段)
     */
    @Field(
            type = FieldType.Date,
            pattern = "yyyy-MM-dd'T'HH:mm:ss", // ES默认的日期格式
            name = "create_time" // 显式指定对应ES的create_time字段
    )
    private LocalDateTime createTime;

    /**
     * 无参构造函数(Spring Data ES 序列化/反序列化需要)
     */
    public SampleDocument() {
        this.createTime = LocalDateTime.now(); // 默认赋值当前时间
    }

    /**
     * 带参构造函数(快速创建对象,字段与ES索引完全对齐)
     */
    public SampleDocument(String id, String name, Double price, String category) {
        this.id = id; // 商品业务ID(对应ES的id字段)
        this.name = name;
        this.price = price;
        this.category = category;
        this.createTime = LocalDateTime.now(); // 自动赋值创建时间
    }

    /**
     * 重写toString,便于日志打印和调试
     */
    @Override
    public String toString() {
        return "ProductDocument{" +
                "docId='" + docId + '\'' + // ES文档的_id
                ", id='" + id + '\'' +     // 商品业务ID(ES的id字段)
                ", name='" + name + '\'' +
                ", price=" + price +
                ", category='" + category + '\'' +
                ", createTime=" + createTime +
                '}';
    }
}
dart 复制代码
 @Autowired
    private ElasticsearchOperations elasticsearchOperations;

elasticsearchOperations.save();
elasticsearchOperations.delete();
elasticsearchOperations.search();

SampleDocument sampleDocument = elasticsearchOperations.get(id, SampleDocument.class); //根据id查询
elasticsearchOperations.delete(id, SampleDocument.class); // 根据id删除

//其他查询
    public List<SampleDocument> searchDocuments(String keyword) {
        Criteria criteria = new Criteria("name").matches(keyword) // 分词匹配
                .or(new Criteria("category").is(keyword)); // 全量匹配
        Query query = new CriteriaQuery(criteria);
        
        SearchHits<SampleDocument> searchHits = elasticsearchOperations.search(query, SampleDocument.class);
        
        return searchHits.stream()
                .map(SearchHit::getContent)
                .collect(Collectors.toList());
    }
相关推荐
xing-xing2 小时前
Spring Data Elasticsearch
后端·spring·elasticsearch
薛定e的猫咪2 小时前
【Bayesian Analysis 2023】大数据背景下的分布式贝叶斯模型选择
大数据·分布式·算法·数学建模
江畔何人初2 小时前
hadoop中HDFS框架、YARN框架各组件职责与对比
大数据·hadoop·hdfs
JZC_xiaozhong2 小时前
DCS分散控制系统与MES集成:实现制造过程数据贯通的关键路径
大数据·运维·制造·etl工程师·bpm·数据集成与应用集成·业务流程管理
TDengine (老段)2 小时前
TDengine IDMP 数据可视化——状态时间线
大数据·数据库·ai·信息可视化·时序数据库·tdengine·涛思数据
DolphinDB智臾科技2 小时前
V3.00.5 & 2.00.18 更新!TPC-H 性能跃升,MPP 引擎来了…
大数据·数据库·时序数据库·dolphindb
云飞云共享云桌面2 小时前
10人SolidWorks设计团队如何提升SolidWorks软件利用率
大数据·linux·运维·服务器·网络·人工智能
冯RI375II6948714 小时前
CPC认证的流程是怎样的呢
大数据
打码人的日常分享15 小时前
数据中心信息中心信息科管理制度
大数据·运维·网络·云计算·制造