NipGeihou's blog NipGeihou's blog
  • Java

    • 开发规范
    • 进阶笔记
    • 微服务
    • 快速开始
    • 设计模式
  • 其他

    • Golang
    • Python
    • Drat
  • Redis
  • MongoDB
  • 数据结构与算法
  • 计算机网络
  • 应用

    • Grafana
    • Prometheus
  • 容器与编排

    • KubeSphere
    • Kubernetes
    • Docker Compose
    • Docker
  • 组网

    • TailScale
    • WireGuard
  • 密码生成器
  • 英文单词生成器
🍳烹饪
🧑‍💻关于
  • 分类
  • 标签
  • 归档

NipGeihou

我见青山多妩媚,料青山见我应如是
  • Java

    • 开发规范
    • 进阶笔记
    • 微服务
    • 快速开始
    • 设计模式
  • 其他

    • Golang
    • Python
    • Drat
  • Redis
  • MongoDB
  • 数据结构与算法
  • 计算机网络
  • 应用

    • Grafana
    • Prometheus
  • 容器与编排

    • KubeSphere
    • Kubernetes
    • Docker Compose
    • Docker
  • 组网

    • TailScale
    • WireGuard
  • 密码生成器
  • 英文单词生成器
🍳烹饪
🧑‍💻关于
  • 分类
  • 标签
  • 归档
  • 消息队列

  • 搜索引擎

    • ElasticSearch

      • 概述
      • 环境搭建
      • 操作 - Restful
      • 操作 - RestClinet(弃用)
        • 初始化JavaRestClient
        • 索引库
          • 创建
          • 删除
          • 判断是否存在
        • 文档
          • 创建
          • 批量创建
          • 查询
          • 修改
          • 删除
        • 文档 - 搜索(列表查询)
          • 全文检索查询
          • 精确查询
          • 复合查询-boolean query
          • 组合查询-function score
          • 排序和分页
          • 距离排序
          • 高亮
          • DSL构建
          • 高亮结果解析
      • 操作 - Spring Data
      • 示例 - 黑马旅游
      • 查询 - 数据聚合
      • ElasticSearch - 自动补全与自定义分词器
      • ElasticSearch - 数据同步
      • ElasticSearch - 集群
  • 中间件
  • 搜索引擎
  • ElasticSearch
NipGeihou
2022-04-30
目录

操作 - RestClinet(弃用)

注意

  • 此依赖已被官方启用,转用 https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/_getting_started.html
  • Elasticsearch 版本最高支持到 7

# 初始化 JavaRestClient

引入 es 的 RestHighLevelClient 依赖

<!-- elasticsearch -->
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.12.1</version>
</dependency>

因为 SpringBoot 默认的 ES 版本是 7.6.2,所以我们需要覆盖默认的 ES 版本

<properties>
    <java.version>1.8</java.version>
    <elasticsearch.version>7.12.1</elasticsearch.version>
</properties>

初始化 RestHighLevelClient

private RestHighLevelClient client;
/**
 * 初始化
 */
@BeforeEach
public void init() {
    client = new RestHighLevelClient(RestClient.builder(
            HttpHost.create("http://10.10.10.77:9200"))
    );
}

# 索引库

# 创建

@Test
void createHotelIndex() throws IOException {
    // 1.创建Request对象
    CreateIndexRequest request = new CreateIndexRequest("hotel");

    // 2.准备请求的参数:DSL语句
    request.source(MAPPING_TEMPLATE, XContentType.JSON);

    // 3.发送请求
    client.indices().create(request, RequestOptions.DEFAULT);

}

MAPPING_TEMPLATE 为请求的 JSON 字符串

# 删除

    /**
     * 判断索引库是否存在.
     */
    @Test
    void isExistsHotelIndex() throws IOException {
        // 1.创建Request对象
        boolean exists = client.indices().exists(new GetIndexRequest("hotel"), RequestOptions.DEFAULT);
        System.out.println(exists);
    }

# 判断是否存在

/**
 * 判断索引库是否存在.
 */
@Test
void isExistsHotelIndex() throws IOException {
    // 1.创建Request对象
    boolean exists = client.indices().exists(new GetIndexRequest("hotel"), RequestOptions.DEFAULT);
    System.out.println(exists);
}

# 文档

# 创建

/**
 * 创建文档,通过数据库
 */
@Test
public void createDocument() throws IOException {
    Hotel hotel = hotelService.getById(61083L);
    // 转换为文档类型
    HotelDoc hotelDoc = new HotelDoc(hotel);

    IndexRequest request = new IndexRequest("hotel").id(hotel.getId().toString());
    request.source(JSON.toJSONString(hotelDoc), XContentType.JSON);
    client.index(request, RequestOptions.DEFAULT);

}

# 批量创建

/**
 * 批量新增文档
 */
@Test
public void bulkDocument() throws IOException {
    // 获取所有酒店
    List<Hotel> hotelList = hotelService.list();

    // 准备请求
    BulkRequest request = new BulkRequest();

    // 转换为文档类型
    for (Hotel hotel : hotelList) {
        HotelDoc hotelDoc = new HotelDoc(hotel);
        // 准备请求,添加多个request
        request.add(new IndexRequest("hotel").id(hotel.getId().toString())
                .source(JSON.toJSONString(hotelDoc), XContentType.JSON));
    }


    // 发送请求
    client.bulk(request, RequestOptions.DEFAULT);

}

# 查询

/**
 * 查询文档
 * @throws IOException
 */
 @Test
 public void getDocument() throws IOException {

     // 准备请求

     // 发送请求
     GetRequest request = new GetRequest("hotel", "61083");
     GetResponse response = client.get(request, RequestOptions.DEFAULT);

     // 解析响应
     String json = response.getSourceAsString();

     HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);

     System.out.println(hotelDoc);

 }

# 修改

/**
 * 修改文档
 * @throws IOException
 */
@Test
public void updateDocument() throws IOException {
    // 准备请求
    UpdateRequest request = new UpdateRequest("hotel", "61083");

    // 准备请求参数
    request.doc(
            "price", "952",
            "starName", "四钻"
    );


    // 发送请求
    client.update(request, RequestOptions.DEFAULT);

}

# 删除

/**
 * 删除文档
 * @throws IOException
 */
@Test
public void deleteDocument() throws IOException {
    DeleteRequest request = new DeleteRequest("hotel", "61083");
    client.delete(request, RequestOptions.DEFAULT);
}

# 文档 - 搜索(列表查询)

image-20220506113734315

    @Test
    void testMatchAll() throws IOException {
        // 创建一个请求
        SearchRequest request = new SearchRequest("hotel");
        // 设置查询条件
        request.source().query(
                // 匹配所有
                QueryBuilders.matchAllQuery()
        );
        // 执行请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        // 解析响应
        SearchHits hits = response.getHits();
        // 获取总记录数
        long total = hits.getTotalHits().value;
        System.out.println("总记录数:" + total);
        // 获取每条记录
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit hit : searchHits) {
            // 获取每条记录的_source
            String json = hit.getSourceAsString();
            // 反序列化
            HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
            // 输出
            System.out.println(hotelDoc);
        }
        System.out.println(response);
    }

RestAPI 中其中构建 DSL 是通过 HighLevelRestClient 中的 resource() 来实现的,其中包含了查询、排序、分页、高亮等所有功能:

image-20220506114504488

RestAPI 中其中构建查询条件的核心部分是由一个名为 QueryBuilders 的工具类提供的,其中包含了各种查询方法:

image-20220506114531325

查询的基本步骤是:

  1. 创建 SearchRequest 对象
  2. 准备 Request.source (),也就是 DSL。
    1. QueryBuilders 来构建查询条件
    2. 传入 Request.source () 的 query () 方法
  3. 发送请求,得到结果
  4. 解析结果(参考 JSON 结果,从外到内,逐层解析)

# 全文检索查询

全文检索的 match 和 multi_match 查询与 match_all 的 API 基本一致。差别是查询条件,也就是 query 的部分。 同样是利用 QueryBuilders 提供的方法:

// 单字段查询
QueryBuilders.matchQuery("all", "如家");
// 多字段查询
QueryBuilders.multiMatchQuery("如家", "name", "business");

对应

GET /hotel/_search
{
  "query": {
    "match": {
      "all": "如家"
    }
  }
}

GET /hotel/_search
{
  "query": {
    "multi_match": {
      "query": "如家",
      "fields": ["brand", "name"]
    }
  }
}

Example:

点击查看
    @Test
    void testMatch() throws IOException {
        // 创建一个请求
        SearchRequest request = new SearchRequest("hotel");
        // 设置查询条件
        request.source().query(
                QueryBuilders.matchQuery("all", "如家")
        );
        // 执行请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        handleResponse(response);
    }

# 精确查询

// 词条查询
QueryBuilders.termQuery("city", "杭州"); 
// 范围查询
QueryBuilders.rangeQuery("price").gte(100).lte(150);

对应

GET /hotel/_search
{
  "query": {
    "term": {
      "city": "杭州"
    }
  }
}
GET /hotel/_search
{
  "query": {
    "range": {
      "price": { "gte": 100, "lte": 150 }
    }
  }
}

# 复合查询 - boolean query

精确查询常见的有 term 查询和 range 查询,同样利用 QueryBuilders 实现:

// 创建布尔查询
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
// 添加must条件
boolQuery.must(QueryBuilders.termQuery("city", "杭州")); 
// 添加filter条件
boolQuery.filter(QueryBuilders.rangeQuery("price").lte(250));
GET /hotel/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": { "city": "杭州" }
        }
      ],
      "filter": [
        {
          "range": {
            "price": { "lte": 250 }
          }
        }
      ]
    }
  }
}

Example:

点击查看
    @Test
    void testBool() throws IOException {
        // 创建一个请求
        SearchRequest request = new SearchRequest("hotel");
        // 设置查询条件
        request.source().query(
                QueryBuilders.boolQuery()
                        .must(QueryBuilders.termQuery("city", "杭州"))
                        .filter(QueryBuilders.rangeQuery("price").lte(250))
        );
        // 执行请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        handleResponse(response);
    }

# 组合查询 - function score

image-20220507200110361

# 排序和分页

搜索结果的排序和分页是与 query 同级的参数,对应的 API 如下:

// 查询
request.source().query(QueryBuilders.matchAllQuery());
// 分页
request.source().from(0).size(5);
// 价格排序
request.source().sort("price", SortOrder.ASC);
GET /indexName/_search
{
  "query": {
    "match_all": {}
  },
  "from": 0,
  "size": 5, 
  "sort": [
    {
      "FIELD": "desc"  
    },
  ]
} 

Example:

点击查看
    @Test
    void testPageAndSort() throws IOException {
        int page = 2, size = 5;

        // 创建一个请求
        SearchRequest request = new SearchRequest("hotel");
        // 设置查询条件
        request.source()
                .query(
                        QueryBuilders.matchAllQuery()
                )
                // 排序
                .sort("price", SortOrder.ASC)
                // 分页
                .from((page - 1) * size).size(5)
        ;

        // 执行请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        handleResponse(response);
    }

# 距离排序

image-20220507172800977

# 高亮

高亮 API 包括请求 DSL 构建和结果解析两部分

# DSL 构建

request.source().highlighter(new HighlightBuilder()
                             .field("name")
                             // 是否需要与查询字段匹配
                             .requireFieldMatch(false)
                            );
GET /hotel/_search
{
  "query": {
    "match": {
      "all": "如家"
    }
  },
  "highlight": {
    "fields": {
      "name": {
        "require_field_match": "false"
      }
    }
  }
}

Example:

点击查看
    @Test
    void testHighlight() throws IOException {

        // 创建一个请求
        SearchRequest request = new SearchRequest("hotel");
        // 设置查询条件
        request.source()
                // 查询
                .query(
                        QueryBuilders.matchQuery("all", "如家")
                )
                // 高亮
                .highlighter(
                        new HighlightBuilder()
                                .field("name").requireFieldMatch(false)
                )
        ;

        // 执行请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        handleResponse(response);
    }

# 高亮结果解析

image-20220507113543522

    private void handleResponse(SearchResponse response) {
        // 解析响应
        SearchHits hits = response.getHits();
        // 获取总记录数
        long total = hits.getTotalHits().value;
        System.out.println("总记录数:" + total);
        // 获取每条记录
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit hit : searchHits) {
            // 获取每条记录的_source
            String json = hit.getSourceAsString();
            // 反序列化
            HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);

            // 处理高亮内容  start ------------------>
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if (!CollectionUtils.isEmpty(highlightFields)) {
                // 根据字段名称获取高亮内容
                HighlightField nameField = highlightFields.get("name");
                if (Objects.nonNull(nameField)) {
                    // 获取高亮值
                    String name = nameField.getFragments()[0].string();
                    // 覆盖原始值
                    hotelDoc.setName(name);
                }
            }
            // 处理高亮内容  end ------------------>

            // 输出
            System.out.println(hotelDoc);
        }
        System.out.println(response);
    }
上次更新: 2024/03/11, 22:37:05
操作 - Restful
操作 - Spring Data

← 操作 - Restful 操作 - Spring Data→

最近更新
01
Docker Swarm
04-18
02
安全隧道 - gost
04-17
03
Solana最佳实践
04-16
更多文章>
Theme by Vdoing | Copyright © 2018-2025 NipGeihou | 友情链接
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式