d47:Elasticsearch入门

Elasticsearch入门与JavaRestClient实践

1. Elasticsearch入门

Elasticsearch是一个高性能的搜索引擎框架,其核心是通过倒排索引来实现高效的搜索功能。倒排索引的工作原理如下:

将文档(数据)进行分词,基于词条创建索引,通过查询词条来获得文档ID。以下是倒排索引的示意图:
文档1: 小米手机 文档2: 华为手机 文档3: 华为小米充电器 文档4: 小米手环 原始数据 分词处理 生成倒排索引 词条: 小米
文档ID: 1,3,4 词条: 手机
文档ID: 1,2 词条: 华为
文档ID: 2,3 词条: 充电器
文档ID: 3 词条: 手环
文档ID: 4 用户搜索: 华为手机 搜索词分词 得到词条: 华为, 手机 在倒排索引中查找 华为 -> 文档2,3 手机 -> 文档1,2 取交集: 文档2 返回文档2: 华为手机

IK分词器

IK分词器是处理中文语义的分词器,可以通过RESTful风格的请求来测试分词器:

json 复制代码
POST /_analyze
{
  "analyzer": "ik_smart",
  "text": "你好"
}

IK分词器有两种模式:

  • ik_smart:智能切分,粗粒度
  • ik_max_word:最细切分,细粒度

可以通过配置config目录的IKAnalyzer.cfg.xml文件来拓展分词器词库中的词条。

2. 基本概念

Elasticsearch与MySQL的对比:

MySQL 概念/术语 Elasticsearch 概念/术语 说明
Table(表) Index(索引) 索引是文档的集合,类似数据库的表。
Row(行) Document(文档) 文档是一条条的数据,类似数据库的行,文档为JSON格式。
Column(列) Field(字段) 字段是JSON文档中的字段,类似数据库的列。
Schema(表结构) Mapping(映射) 映射是索引中文档的约束,例如字段类型约束,类似数据库的表结构。
SQL DSL DSL是Elasticsearch提供的JSON风格的请求语句,用于定义搜索条件。

Mapping映射

Mapping将实体映射为索引库的文档约束,常见的Mapping属性如下:

属性名 作用 常用取值示例
type 字段数据类型 字符串:text(可分词)、keyword(精确值) 数值:longintegerdoublefloat 布尔:boolean 日期:date 对象:object
index 是否创建倒排索引 true(默认)、false
analyzer 指定分词器 如:ik_max_wordik_smart
properties 定义子字段(object类型) 例如:name.firstNamename.lastName

例如,定义一个Book类的Mapping:

json 复制代码
PUT /book
{
  "mappings": {
    "properties": {
      "id": {
        "type": "long"
      },
      "title": {
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "author": {
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "isbn": {
        "type": "keyword"
      },
      "price": {
        "type": "double"
      },
      "onSale": {
        "type": "boolean"
      },
      "publishDate": {
        "type": "date"
      }
    }
  }
}

3. JavaRestClient

引入依赖

xml 复制代码
<!-- elasticsearch-->
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.12.1</version>
</dependency>

与Elasticsearch连接

java 复制代码
@BeforeEach
public void init(){
    client = new RestHighLevelClient(
            RestClient.builder(
                    new HttpHost("192.168.142.130", 9200, "http")
            )
    );
}

@AfterEach
public void destroy(){
    try {
        client.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

4. 索引库与文档操作

索引库操作

功能 请求方式 请求路径 请求参数说明
查询用户 GET /users/{id} 路径参数:用户ID
新增用户 POST /users 请求体:JSON格式用户对象
修改用户 PUT /users/{id} 路径参数:用户ID + JSON格式用户对象
删除用户 DELETE /users/{id} 路径参数:用户ID
创建索引库
json 复制代码
PUT /items
{
  "mappings": {
    "properties": {
      ......
    }
  }
}

对应到JavaRestClient的操作:

java 复制代码
@Test
void testCreateHotelIndex() throws IOException {
    // 创建请求
    CreateIndexRequest request = new CreateIndexRequest("items");
    // 设置参数
    request.source(MAPPING_TEMPLATE, XContentType.JSON);
    // 发起请求
    client.indices().create(request, RequestOptions.DEFAULT);
}
获取和删除索引
java 复制代码
@Test
void testGetHotelIndex() throws IOException {
    GetIndexRequest request = new GetIndexRequest("items");
    GetIndexResponse exists = client.indices().get(request, RequestOptions.DEFAULT);
    System.out.println(exists);
}

@Test
void testDeleteHotelIndex() throws IOException {
    DeleteIndexRequest request = new DeleteIndexRequest("items");
    client.indices().delete(request, RequestOptions.DEFAULT);
}

文档操作

插入一条数据
java 复制代码
@Test
void testIndexDocument() throws IOException {
    // 准备数据
    Item item = itemService.getById(317578L);
    ItemDoc itemDoc = BeanUtil.copyProperties(item, ItemDoc.class);

    // 创建请求
    IndexRequest request = new IndexRequest("items").id(itemDoc.getId());
    // 请求参数
    request.source(JSONUtil.toJsonStr(itemDoc),XContentType.JSON);
    // 发送请求
    client.index(request, RequestOptions.DEFAULT);
}
获取数据
java 复制代码
@Test
void testGetDocument() throws IOException {
    // 创建请求
    GetRequest request = new GetRequest("items", "317578");
    // 发送请求
    GetResponse response = client.get(request, RequestOptions.DEFAULT);
    // 获取数据
    String json = response.getSourceAsString();
    // 转换成对象
    ItemDoc itemDoc = JSONUtil.toBean(json, ItemDoc.class);
    System.out.println(itemDoc);
}
删除数据
java 复制代码
@Test
void testDeleteDocument() throws IOException {
    DeleteRequest request = new DeleteRequest("items", "317578");
    client.delete(request, RequestOptions.DEFAULT);
}
文档更新

Elasticsearch的文档更新分为全量和增量两种方式:

  • 全量更新:直接替换掉整个旧文档

    json 复制代码
    PUT /索引库/_doc/文档id
    {
        "字段名":"值"
        ......
        //必须包含所有的完整字段
    }
  • 增量更新:处理部分数据

    json 复制代码
    POST /索引库/_update/文档id
    {
        "doc":{
            "字段名":"newValue"
        }
    }

对应到JavaRestClient的操作:

java 复制代码
@Test
void testUpdateDocument() throws IOException {
    UpdateRequest request = new UpdateRequest("items", "317578");
    request.doc(
            "price", 9999
    );
    client.update(request, RequestOptions.DEFAULT);
}
批处理

一次性进行多条文档操作:

java 复制代码
@Test
void testBulkDoc() throws IOException {
    int pageNo = 1;int pageSize = 500;
    while ( true){
        // 准备请求参数
        Page<Item> page = itemService.lambdaQuery()
                .eq(Item::getStatus, 1)
                .page(Page.of(pageNo, pageSize));
        List<Item> records = page.getRecords();
        if(records == null || records.isEmpty()){
            return;
        }
        BulkRequest request = new BulkRequest();
        for(Item item : records){
            ItemDoc itemDoc = BeanUtil.copyProperties(item, ItemDoc.class);
            request.add(new IndexRequest("items").source(JSONUtil.toJsonStr(itemDoc),XContentType.JSON));
        }
        client.bulk(request, RequestOptions.DEFAULT);
        pageNo++;
    }
}

查询

在进行查询时,获取的response结构大致如下:

json 复制代码
{
  "took" : 109,
  "timed_out" : false,
  "_shards" : {
    "total" : 6,
    "successful" : 6,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 10000,
      "relation" : "gte"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : ".kibana-event-log-7.12.1-000001",
        "_type" : "_doc",
        "_id" : "pUdzJJoBn6OMEyyxh_b6",
        "_score" : 1.0,
        "_source" : {
          "@timestamp" : "2025-10-27T06:54:56.044Z",
          "event" : {
            "provider" : "eventLog",
            "action" : "starting"
          },
          "message" : "eventLog starting",
          "ecs" : {
            "version" : "1.6.0"
          },
          "kibana" : {
            "server_uuid" : "d2a0f545-6cd0-43cd-ae8e-372cfd963bf6"
          }
        }
      }
    ]
  }
}

要获取真正的数据部分,需要解析其层级:

java 复制代码
private static void extractedResponse(SearchResponse response) {
    // 解析结果
    SearchHits hits = response.getHits();
    Long total = hits.getTotalHits().value;
    SearchHit[] items = hits.getHits();
    for(SearchHit item : items){
        String json = item.getSourceAsString();
        ItemDoc itemDoc = JSONUtil.toBean(json, ItemDoc.class);
        System.out.println(itemDoc);
    }
}

条件查询

Elasticsearch的条件查询支持多种子句,如下表所示:

子句名 作用描述 类比逻辑 是否参与算分
must 必须匹配 与 AND
should 选择性匹配(可配置最少匹配数) 或 OR
must_not 必须不匹配 非 NOT
filter 必须匹配 ------

例如,使用mustfilter进行查询:

java 复制代码
@Test
void testMatchQuery() throws IOException {
    SearchRequest request = new SearchRequest("items");
    request.source()
            .query(
                    QueryBuilders.boolQuery()
                            .must(QueryBuilders.matchQuery("name", "小米"))
                            .filter(QueryBuilders.termQuery("category", "手机"))
                            .filter(QueryBuilders.rangeQuery("price").lte(20000).gte(1000))
            );
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    extractedResponse(response);
}

排序与分页

Elasticsearch支持排序和分页操作,示例如下:

java 复制代码
@Test
void testPageQuery() throws IOException {
    int  pageNo = 1;int pageSize = 5;
    SearchRequest request = new SearchRequest("items");
    request.source()
            .query(QueryBuilders.matchAllQuery())
            .from((pageNo - 1) * pageSize)
            .size(pageSize)
            .sort("price", SortOrder.ASC)
            .sort("sold", SortOrder.DESC);
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    extractedResponse(response);
}
```v
相关推荐
ACGkaka_2 小时前
ES 学习(九)从文本到词元:分词器如何“拆解“你的数据
大数据·学习·elasticsearch
Elastic 中国社区官方博客2 小时前
如何使用 LogsDB 降低 Elasticsearch 日志存储成本
大数据·运维·数据库·elasticsearch·搜索引擎·全文检索·可用性测试
A__tao3 小时前
一键实现 SQL 转 Elasticsearch Mapping(支持字段注释 + meta 描述)
数据库·sql·elasticsearch
老纪的技术唠嗑局1 天前
告别OpenClaw配置丢失——Mindkeeper内测版邀测
大数据·elasticsearch·搜索引擎
Elasticsearch1 天前
使用 Elasticsearch + Jina embeddings 进行无监督文档聚类
elasticsearch
勇哥的编程江湖1 天前
flinkcdc streaming 同步数据到es记录过程
大数据·elasticsearch·flink·flinkcdc
曾阿伦1 天前
Elasticsearch 7.x 常用命令备忘录
大数据·elasticsearch·搜索引擎
斯特凡今天也很帅1 天前
Elasticsearch数据库专栏(二)DSL语句总结(更新中)
大数据·elasticsearch·搜索引擎
要记得喝水1 天前
适用于 Git Bash 的脚本,批量提交和推送多个仓库的修改
git·elasticsearch·bash
二十七剑1 天前
Elasticsearch的索引问题
大数据·elasticsearch·搜索引擎