spring boot集成Elasticsearch-SpringBoot(25)

  1. Elasticsearch—搜索应用服务器

1.1 什么是搜索引擎

搜索引擎(search engine )通常意义上是指:根据特定策略,运用特定的爬虫程序从互联网上搜集信息,然后对信息进行处理后,为用户提供检索服务,将检索到的相关信息展示给用户的系统。

而我们讲解的是捜索的索引和检索,不涉及爬虫程序的内容爬取。大部分公司的业务也不会有爬取工作,而只提供查询服务,而且Elasticsearch也只是提供这方面的功能。

1.2认识 Elasticsearch

Elasticsearch是一个分布式、RESTful风格的搜索和数据分析引撃。通过它,能够执行及合并多种类型的搜索(结构化数据、非结构化数据、地理位置、指标),解决不新涌现出的各种需求。

Elasticsearch使用的是标准的RESTful风格的API,使用JSON提供多种语言(Java、 Python、.Net、SQL和PHP)的支持,它可以快速地存储、搜索和分析海量数据。

Elasticsearch是用Java语言开发的,并使用Lucene作为其核心来实现所有索引和搜索的功能。它的目的是:通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。

Elasticsearch是一个开源的高扩展的分布式全文检索引擎,可以近乎实时地存储、检索数据; 本身扩展性很好,允许多台服务器协同工作,每台服务器可以运行多个实例。单个实例称为一个节 (node), 一组节点构成一个集群(cluster)。分片是底层的工作单元,文档保存在分片内,分片又被分配到集群内的各个节点里,每个分片仅保存全部数据的一部分。

当Elasticsearch的节点启动后,它会使用多播(multicast)或单播(用户更改了配置)寻找集群中的其他节点,并与之建立连接。

1.3 Elasticsearch 应用案例

  • GitHub: 2013年年初,GitHub把Solr缓存改成了Elasticsearch,以便用户搜索20TB 的数据,包括13亿个文件和1300亿行代码。
  • 维基百科:启动以Elasticsearch为基础的核心搜索架构SoundCloud,为1.8亿用户提供即时而精准的音乐搜索服务。
  • 百度:百度使用Elasticsearch作为数据分析引擎,20多个业务税采集服务器上的各类数据及用户自定义数据,通过对各种数据进行多维分析,辅助定位异常。其单集群最大100台机器,200个Elasticsearch节点,每天导入超过30TB的数据。

除这些公司外,Stack Overflow、新浪、阿里、360、携程、有赞、苏宁都在使用它。它被广泛地用于各大公司的站内搜索、IT系统搜索(OA、CRM、ERP)、数据分析等工作中。

1.4 对比 Elasticsearch 与 MySQL

尽管将Elasticsearch与MySQL进行对比并不科学,但是这样的对比能区分Elasticsearch 和MySQL数据库的区别,便于快速用熟悉的知识来理解Elasticsearch 。所以,本节采用对比的方式来讲解Elasticsearch。Elasticsearch与MySQL的结构对比见表13-1。

spring boot集成Elasticsearch-SpringBoot(25)

图 13-1

  • 关系型数据库中的数据库,相当于Elasticsearch中的索引(index )。
  • 一个数据库下面有多张表(table),相当于一个索引(index)下面有多个类型(type)。
  • 一个数据库表(table)下的数据由多行(row)多列(column属性)组成,相当于一个 type由多个文档(document)和多个field组成。
  • 在关系型数据库中,schema定义了表、每个表的字段,还有表和字段之间的关系;在 Elasticsearch中,mapping定义索引下的type的字段处理规则,即索引如何建立、索引类型、 是否保存原始索引 JSON文档、是否压缩原始JSON文档、是否需要分词处理、如何进行分词处理等。
  • 在 MySQL 数据库中的增(insert )、删(delete )、改(update )、查 ( select)操作相 当于 Elasticsearch 中的增(put/post )、删(delete )、改(update )、查(get)

客户端主要通过”方法(PUT/POST/GET/ DELETE ) + http://ip:端口/索引名称/类型/主键” 来访问内容。

1.5 认识 ElasticSearchRepository

Spring-data-elasticsearch 是 Spring 提供的操作 Elasticsearch 的数据接口,它封装了大量的基础操作。通过它可以很方便地操作Elasticsearch的数据。

通过继承ElasticsearchRepository来完成基本的CRUD及分页操作,和普通的 JPA没有什 么区别。比如下面实体Product的Repository继承ElasticsearchRepository后,可以在 Elasticsearch文档中进行查找和比较等操作。具体使用方法见以下代码:

@Component
public interface UserRepository extends ElasticsearchRepository<user,long> {
    Optional<user> findById(Long id);
    User findByUsername(String username);
    List<user> findByEmail(String email);
}</user></user></user,long>

ElasticsearchRepository有几个特有的search方法,用来构建一些Elasticsearch查询, 主要由QueryBuilder和SearchQuery两个参数来完成一些特殊查询。

实现类NativeSearchQuery实现了 QueryBuilder和SearchQuery方法,要构建复杂查询, 可以通过构建NativeSearchQuery类来实现。

—般情况下,不是直接新建NativeSearchQuery类,而是使用NativeSearchQueryBuilder 来完成NativeSearchQuery的构建。具体用法见以下代码:

NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
builder.withQuery()
    .withFilter()
    .withSort()
    .withXXX().build();

1.6 认识 ElasticsearchTemplate

ElasticsearchTemplate是Spring对Elasticsearch的API进行的封装,主要用来对索引进行创建、删除等操作。它继承了 ElasticsearchOperations 和 ApplicationContextAware 接口。 ElasticSearchTemplate 提供一些比 ElasticsearchRepository 更底层的方法。

ElasticsearchOperations接口中常用的方法如下。

*
– createlndex()方法:创建索引,返回值为布尔类型数据。
– indexExists()方法:查询索引是否存在,返回值为布尔类型数据。
– putMapping()方法: 创建映射,返回值为布尔类型数据。
– getMapping()方法:得到映射,返回值为一个Map数据。
– deletelndex()方法:删除索引,返回值为布尔类型数据。

1.7 认识注解@Document

注解@Document作用于类,用于标记实体类为文档对象。

存储在Elasticsearch中的一条数据,即是一个文档,类似关系型数据库的一行数据。 Elasticsearch会索引每个文档的内容,以便搜索。它使用JSON格式,将数据存储到Elasticsearch 中,实际上是将JSON格式的字符串发送给了 Elasticsearch。

1.document的核心元数据

document有三个核心元数据,分别是 _index、_type、_id

(1)_index。代表一个document存放在哪个index中,类似的数据放在一个索引中,非类似的数据放在不同的索引中。index中包含了很多类似的document,这些document的field很大一 部分是相同的。索引名称必须小写,不能用下画线开头,不包含逗号。

(2)_type。代表document属于index的哪个类别,一个索引通常会划分为多个type,逻辑 index不同的数据进行分类。type名称可以是大写或小写,但是不能用下画线开头,不能包含逗号。

(3)_id。代表document的唯一标识,与_index和_type —起可以标识和定位一个 document。默认自动创建id,也可以手动指定document的id。

2.document id的手动指定和自动生成

(1)手动指定 document id

如果需要从某些其他系统中导入一些数据到Elasticsearch,则会采用手动指定id的形式,因 为一般情况下系统中已有数据的唯一标识,可以用作Elasticsearch中的document的id。

其语法格式为:

put /index/type/id
{
    "json"
}

(2)自动生成 document id

其语法格式为:

post /index/type
{
    "json"
}

自动生成的id长度为20个字符,URL安全、Base64编码、GUID、分布式系统并行生成时不会发生冲突。

3. document的_source元数据,以及定制返回结果

_source元数据是在创建document时放在body中的JSON数据。在默认情况下,查找数据时会返回全部数据。如果要定制返回结果,则可以指定_source中返回哪些field

例如:

GET /_index/_type/1?_source=field

1.8 管理索引

1. 创建索引

(1)根据类的信息自动生成创建索引

下面代码是根据实体类创建一个名为”ec” 的索引,并定义type是”product”。由于是单机环境,所以定义副本为0,分片为默认值5。

@Data
@Document(indexName = "user",type = "user",replicas = 0,shards = 5)
public class User implements Serializable {
    private int id;
    private String username;
    private String password;
}

代码解释如下。

  • indexName :对应索引库名称,可以理解为数据库名。必须小写,否则会报 “org.elasticsearch.indices.InvalidlndexNameException”异常。
  • type:对应在索引库中的类型,可以将其理解为”表名”
  • shards:分片数量,默认值为5。
  • replicas:副本数量,默认值为1。如果是单机环境,则健康状态为”yellow”。如果要成为 “green”,则指定值为0即可。

(2)手动创建索引

可以使用createindex方法手动指定indexName和Settings,再进行映射。在使用前,要先注入ElasticsearchTemplate,使用方法如下。

  • 根据索引名创建索引:
elasticsearchTemplate.createIndex("indexname");
  • 根据类名创建索引:
elasticsearchTemplate.createIndex(User.class);

2. 查询索引

  • 根据索引名查询:
elasticsearchTemplate.indexExists("indexname");
  • 根据类名查询:
elasticsearchTemplate.indexExists(User.class);

3. 删除索引

可以根据索引名和类名对索引进行删除。

  • 根据索引名删除:
elasticsearchTemplate.deleteIndex("indexname");
  • 根据类名删除:
elasticsearchTemplate.deleteIndex(User.class);

2. 用ELK管理Spring Boot应用程序的日志

ELK 是 Elasticsearch+Logstash+Kibana 的简称。

Logstash负责将数据信息从输入端传输到输出端,比如将信息从MySQL传入Elasticsearch, 还可以根据自己的需求在中间加上滤网。Logstash提供了很多功能强大的滤网,以满足各种应用场景。

Logstash有以下两种工作方式。

  • 每一台机器启动一个Logstash服务,读取本地的数据文件,生成流传给Elasticsearch。
  • Logback引入Logstash包,然后直接生产JSON流,传给一个中心的Logstash服务器,Logstash服务器再传给Elasticsearch,最后,Elasticsearch将其流传给Kibana。

Kibana是一个开源的分析与可视化平台,和Elasticsearch —起使用。可以用Kibana搜索、 查看、交互存放在Elasticsearch索引里的数据。使用各种不同的图标、表格、地图等,Kibana能够很轻昜地展示高级数据分析与可视化。

ELK架构为数据分布式存储、日志解析和可视化创建了一个功能强大的管理链。三者相互配合, 取长补短,共同完成分布式大数据处理工作。

2.1 安装 Elasticsearch

(1)通过官网下载Elasticsearch。

(2)在下载完成后,首先将其解压到合适的目录,然后进入解压目录下的bin目录,双击 bat文件启动Elasticsearch。这里需要确保安装的Java版本在1.8及以上。

(3)访问”http://localhost:9200/”,当看到返回一串JSON格式的代码时,则说明已经安装成功了。

根据应用需要,还可以安装Elasticsearch必要的一些插件,如Head、kibana、IK (中文分 词)、graph。

2.2 安装 Logstash

1.安装 Logstash

(1)访问 Elasticsearch 官网下载 Logstash

(2)将下载文件解压到自定义的目录即可。

2. 配置 Logstash

(1 )在解压文件的config目录下新建log4j_to_es.conf文件,写入以下代码:

input {
    beats {
        port => 5044
        codec => "json"
    }
}

output {
    elasticsearch {
        hosts => "127.0.0.1:9200"
        codec => json
    }
}

这里一定要注意:这是UTF-8的格式,不要帯BOM。如果启动时岀现错误,则可以用”logstash -f ../config/xxx.conf -t”命令检查配置文件是否错误。

(2)新建文件 run.bat。写入代码 logstash -f .\config\log4j_to_es.conf保存。然后双击该配置文件,启动Logstash。

(3)访问 localhost:9600 如出现以下內容,则代表配置成功。

{"host":"DESKTOP-0VSQ1JE","version":"8.3.3","http_address":"127.0.0.1:9600",
 "id":"f9a14845-005b-42f2-8725-9b3f67dafe86","name":"DESKTOP-0VSQ1JE",
 "ephemeral_id":"9ffa0b64-c9bb-4385-8924-6565b4cd8167","status":"green",
 "snapshot":false,"pipeline":{"workers":8,"batch_size":125,"batch_delay":50},
 "build_date":"2022-07-23T19:31:54Z","build_sha":"0205f0c5f2ff21118c161e769e8f2bbb79ee81a3",
 "build_snapshot":false}

2.3 安装Kibana

Kibana是官方推出的Elasticsearch数据可视化工具。

(1)通过访问Elasticsearch官网下载Kibana。

(2)解压下载的压缩文件,进入解压目录,双击Kibana目录的bin/kibana.bat,以启动 Kibana,当岀现以下提示时,代表启动成功。

[2022-08-16T16:30:45.443+08:00][INFO ][status] Kibana is now available (was degraded)

(3)访问localhost:5601就可以逬入Kibana控制台。

单击控制台左边导航栏的”Dev-tools”按钮,可以进入Dev-tools界面。单击”Get to work”, 然后在控制台输入”GET/_cat/health?”命令,可以查看服务器状态。如果在右侧返回的结果中看到green或yellow ,则表示服务器状态正常。

2.4 配置 Spring Boot 项目

(1)添加项目依赖

<dependency>
    <groupid>org.springframework.boot</groupid>
    <artifactid>spring-boot-starter-log4j</artifactid>
    <version>1.3.6.RELEASE</version>
</dependency>
<dependency>
    <groupid>net.logstash.logback</groupid>
    <artifactid>logstash-logback-encoder</artifactid>
    <version>7.2</version>
</dependency>

(2)添加配置文件logback.xml,这里在Spring Boot项目里添加一个配置又件,见以下代码:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <destination>localhost:9601</destination>
        <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder">
    </encoder></appender>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder charset="UTF-8">
            <pattern>%d{HH:mm:ss.SSS}[%thread]%-5level %logger - %msg%n</pattern>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="LOGSTASH">
        <appender-ref ref="STDOUT">
    </appender-ref></appender-ref></root>
</configuration>

2.5 创建日志计划任务

在Spring Boot项目中创建logTest类,用于测试将日志通过Logstash发送到Elasticsearch, 见以下代码:

  1. Spring Boot集成Elasticsearch

实现增加、删除、修改、查询文档的功能

3.1 集成 Elasticsearch

Spring Boot 提供了 Starter ( spring-boot-starter-data-elasticsearch )来集成 Elasticsearch

  • 优点:开发速度快,不要求熟悉Elasticsearch的一些API,能快速上手。即使之前对 Elasticsearch不了解,也能通过方法名或SQL语句快速写岀自己需要的逻辑。而具体转换成API层的操作则是由框架底层实现的。
  • 缺点:使用的Spring Boot的版本Elasticsearch的版本也有了要求,不能超过某些版本号,在部署时需要注意。如果采用API方式,则能解决这个问题。

(1)添加依赖

<dependency>
    <groupid>org.springframework.data</groupid>
    <artifactid>spring-data-elasticsearch</artifactid>
</dependency>

(2)添加application.yml配置

spring:
  data:
    elasticsearch:
      repositories:
        enabled: true #&#x662F;&#x5426;&#x5F00;&#x542F;&#x672C;&#x5730;&#x5B58;&#x50A8;
      cluster-nodes: 127.0.0.1:9200
      cluster-name: elasticsearch

3.2 创建实体

(1)创建实体

这里根据类的信息自动生成,也可以手动指定索引名称。ElasticsearchTemplate中提供了创建素引的API,因为进行本机测试,没做集群,所以replicas副本先设置为0。见以下代码:

package com.intehel.demo.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

import java.io.Serializable;

@Document(indexName = "ec",replicas = 0,shards = 5,type = "product")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product implements Serializable {
    //@Id&#x6CE8;&#x89E3;&#x5FC5;&#x987B;&#x662F;org.springframework.data.annotation.Id;
    @Id
    private Long id;
    //ik_max_word&#x4F7F;&#x7528;ik&#x5206;&#x8BCD;&#x5668;
    @Field(type = FieldType.Text,analyzer = "ik_max_word")
    private String name;
    //&#x5728;&#x5B58;&#x50A8;&#x6570;&#x636E;&#x65F6;&#xFF0C;&#x4E0D;&#x4F1A;&#x5BF9;category&#x8FDB;&#x884C;&#x5206;&#x8BCD;
    @Field(type = FieldType.Keyword)
    private String category;
    //&#x4EF7;&#x683C;
    @Field(type = FieldType.Double)
    private Double price;
    //index = false &#x8868;&#x793A;&#x4E0D;&#x5EFA;&#x7ACB;&#x7D22;&#x5F15;
    @Field(index = false,type = FieldType.Keyword)
    private String images;
    private String body;
}

代码解释如下,

  • @ld注解:作用于成员变量,标记一个字段作为id主键。
  • @Field注解:作用于成员变量,标记为文档的字段,需要指定字段映射属性type。
  • index:是否索引,布尔类型,默认为true。
  • store:是否存储,布尔类型,默认为false,
  • analyzer;分词器名称,这里的ik_max_word即使用IK分词器。

(2)创建数据操作接口

package com.intehel.demo.repository;

import com.intehel.demo.domain.Product;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.Optional;

public interface ProductRepository extends ElasticsearchRepository<product,long> {
    @Override
    Optional<product> findById(Long id);
    Product findByName(String name);
}</product></product,long>

3.3 实现增加、删除、修改和查询文档的功能

在测试类中,实Elasticsearch文档进行增加、删除、修改和查询的功能,见以下代码:

查看代码

&#xA0;package com.intehel.demo;

import com.intehel.demo.domain.Product;
import com.intehel.demo.domain.User;
import com.intehel.demo.repository.ProductRepository;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.core.QueueBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Sort;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Optional;

@SpringBootTest
@RunWith(SpringRunner.class)
class ElasticApplicationTests {
    private Integer PAGESIZE = 10;
    @Autowired
    private ProductRepository productRepository;
    @Test
    public void save(){
        long id = System.currentTimeMillis();
        Product product = new Product(id,"&#x7EA2;&#x5BCC;&#x58EB;","&#x6C34;&#x679C;",7.99,"jpg","&#x6D4B;&#x8BD5;");
        try {
            productRepository.save(product);
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println(product.getId());
    }
    @Test
    public void getProduct(){
        Product product = productRepository.findByName("&#x7EA2;&#x5BCC;&#x58EB;");
        System.out.println(product.getId());
    }
    @Test
    public void updateProduct(){
        long id = 1660653233939L;
        Product product = new Product(id,"&#x70E4;&#x51B7;&#x9762;","&#x5C0F;&#x5403;",7.00,"jpg","&#x6D4B;&#x8BD5;");
        productRepository.save(product);
    }
    @Test
    public void getProductById(){
        Optional<product> product = productRepository.findById(1660653233939L);
        System.out.println(product.get().getName()+product.get().getBody());
    }
    @Test
    public void deleteProduct(){
        long id = 1660653233939L;
        productRepository.deleteById(id);
    }
    @Test
    public void getAll(){
        Iterable<product> list = productRepository.findAll(Sort.by("id").ascending());
        for (Product product : list) {
            System.out.println(product);
        }
    }
}</product></product>
  1. Elasticsearch查询

4.1 自定义方法

可以根据Spring Data提供的方法名称,实现自己想自定义的查询功能:无须写实现类,只要继承ElasticsearchRepository接口即可。如”findByTitle”表示根据”title”进行查询,具体方法见表13~2

spring boot集成Elasticsearch-SpringBoot(25)

spring boot集成Elasticsearch-SpringBoot(25)

图 13-2

如果要查询价格在7 ~ 8元的商品,则可以在接口类加上”List

public interface ProductRepository extends ElasticsearchRepository<product,long> {
    @Override
    List<product> findByPriceBetween(Double min, Double max);
}</product></product,long>

然后,在测试类中直接使用自定义的”findByPriceBetween”方法查询出数据,见以下代码:

@Test
public void queryByPriceBetween(){
    Iterable<product> list = productRepository.findByPriceBetween(7.00,8.00);
    for (Product product : list) {
        System.out.println(product);
    }
}</product>

4.2 精准查询

1.单参数 termQuery

用法见以下代码:

QueueBuilder queueBuilder = QueueBuilder.termQuery("&#x5B57;&#x6BB5;&#x540D;","&#x67E5;&#x8BE2;&#x503C;");

它是不分词查询。因为不分词,所以汉字只能查询一个字,而多字母的英语单词算一个字

具体实现见以下代码:

@Test
public void queryByPriceBetween(){
    NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
    nativeSearchQueryBuilder.withQuery(QueryBuilders.termQuery("name","&#x5BCC;"));
    //&#x67E5;&#x8BE2;&#x8BCD;&#xFF0C;&#x53EA;&#x80FD;&#x67E5;&#x8BE2;&#x4E00;&#x4E2A;&#x6C49;&#x5B57;&#xFF0C;&#x6216;&#x4E00;&#x4E2A;&#x82F1;&#x6587;&#x5355;&#x8BCD;
    Page<product> page = productRepository.search(nativeSearchQueryBuilder.build());
    //&#x641C;&#x7D22;&#xFF0C;&#x83B7;&#x53D6;&#x7ED3;&#x679C;
    for (Product product : page){
        System.out.println(product);
    }
}</product>

2.多参数–termsQuery

terms可以提供n个查询的参数对一个字段进行查询,用法见以下代码。注意,这里是term的复数形式terms

QueueBuilder queueBuilder = QueueBuilder.termsQuery(“字段名”,”查询值”,”查询值”);

@Test
public void queryByPriceBetween(){
    NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
    nativeSearchQueryBuilder.withQuery(QueryBuilders.termsQuery("name","&#x5BCC;","&#x5E05;"));
    //&#x67E5;&#x8BE2;&#x8BCD;&#xFF0C;&#x53EA;&#x80FD;&#x67E5;&#x8BE2;&#x4E00;&#x4E2A;&#x6C49;&#x5B57;&#xFF0C;&#x6216;&#x4E00;&#x4E2A;&#x82F1;&#x6587;&#x5355;&#x8BCD;
    Page<product> page = productRepository.search(nativeSearchQueryBuilder.build());
    //&#x641C;&#x7D22;&#xFF0C;&#x83B7;&#x53D6;&#x7ED3;&#x679C;
    for (Product product : page){
        System.out.println(product);
    }

}</product>

3.分词查询– matchQuery

分词查询采用默认的分词器.用法见以下代码

QueueBuilder queueBuilder = QueueBuilder.matchQuery(“字段名”,”查询值”);

具体实现见以下代码:

@Test
public void matchQuery() throws Exception {}{
    NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
    nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("name","&#x7EA2;&#x58EB;"));
    //&#x67E5;&#x8BE2;&#x8BCD;
    Page<product> page = productRepository.search(nativeSearchQueryBuilder.build());
    //&#x641C;&#x7D22;&#xFF0C;&#x83B7;&#x53D6;&#x7ED3;&#x679C;
    for (Product product : page){
        System.out.println(product);
    }
}</product>

4.多字段查询 multiMatchQuery

@Test
public void matchQuery(){
    NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
    nativeSearchQueryBuilder.withQuery(QueryBuilders.multiMatchQuery("&#x7EA2;&#x5BCC;&#x58EB;Gila","name","body"));
    //&#x67E5;&#x8BE2;&#x8BCD;
    Page<product> page = productRepository.search(nativeSearchQueryBuilder.build());
    //&#x641C;&#x7D22;&#xFF0C;&#x83B7;&#x53D6;&#x7ED3;&#x679C;
    for (Product product : page){
        System.out.println(product);
    }
}</product>

4.3 模糊查询

常见的模糊查询的方法有4种

1.左右模糊

QueryBuilders.queryStringQuery("&#x67E5;&#x8BE2;&#x503C;").field("&#x5B57;&#x6BB5;&#x540D;")

具体实现见以下代码:

@Test
public void matchQuery(){
    NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
    nativeSearchQueryBuilder.withQuery(QueryBuilders.queryStringQuery("&#x6211;&#x89C9;&#x5F97;&#x7EA2;&#x5BCC;&#x58EB;&#x597D;&#x5403;").field("name"));
    //&#x67E5;&#x8BE2;&#x8BCD;
    Page<product> page = productRepository.search(nativeSearchQueryBuilder.build());
    //&#x641C;&#x7D22;&#xFF0C;&#x83B7;&#x53D6;&#x7ED3;&#x679C;
    for (Product product : page){
        System.out.println(product);
    }
}</product>

2. 前缀查询— prefixQuery

如果字段没分词,则匹配整个字段前缀,用法见以下代码:

QueryBuilders.prefixQuery("&#x5B57;&#x6BB5;&#x540D;","&#x67E5;&#x8BE2;&#x503C;")

具体实现见以下代码:

@Test
public void matchQuery(){
    NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
    nativeSearchQueryBuilder.withQuery(QueryBuilders.prefixQuery("name","&#x58EB;"));
    //&#x67E5;&#x8BE2;&#x8BCD;
    Page<product> page = productRepository.search(nativeSearchQueryBuilder.build());
    //&#x641C;&#x7D22;&#xFF0C;&#x83B7;&#x53D6;&#x7ED3;&#x679C;
    for (Product product : page){
        System.out.println(product);
    }
}</product>

3. 通配符查询 wildcard query

使用通配符方式进行查询,支持通配符”“和”?”,”“代表任意字符串,”? “代表任意一个字符。

(1)使用通配符”*”

通配符可以匹配多个值,用法见以下代码:

@Test
public void matchQuery(){
    NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
    nativeSearchQueryBuilder.withQuery(QueryBuilders.wildcardQuery("name","*&#x58EB;"));
    //&#x67E5;&#x8BE2;&#x8BCD;
    Page<product> page = productRepository.search(nativeSearchQueryBuilder.build());
    //&#x641C;&#x7D22;&#xFF0C;&#x83B7;&#x53D6;&#x7ED3;&#x679C;
    for (Product product : page){
        System.out.println(product);
    }
}</product>

(2)使用通配符”?”

@Test
public void matchQuery(){
    NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
    nativeSearchQueryBuilder.withQuery(QueryBuilders.wildcardQuery("name","&#x7EA2;&#x5BCC;?"));
    //&#x67E5;&#x8BE2;&#x8BCD;
    Page<product> page = productRepository.search(nativeSearchQueryBuilder.build());
    //&#x641C;&#x7D22;&#xFF0C;&#x83B7;&#x53D6;&#x7ED3;&#x679C;
    for (Product product : page){
        System.out.println(product);
    }
}</product>

4. 分词模糊査询 fuzzy query

分词模糊查询即匹配截取字符串为字前或后加1个词的文档,这里通过增加fuzziness (模糊) 属性来查询,fuzziness的含义是检索的term前后增加或减少n个词的匹配查询。用法见以下代码

QueryBuilders.fuzzyQuery("&#x5B57;&#x6BB5;&#x540D;","&#x67E5;&#x8BE2;&#x503C;").fuzziness(Fuzziness.ONE)

具体实现见以下代码:

@Test
public void matchQuery(){
    NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
    nativeSearchQueryBuilder.withQuery(QueryBuilders.fuzzyQuery("name","&#x58EB;").fuzziness(Fuzziness.ONE));
    //&#x67E5;&#x8BE2;&#x8BCD;
    Page<product> page = productRepository.search(nativeSearchQueryBuilder.build());
    //&#x641C;&#x7D22;&#xFF0C;&#x83B7;&#x53D6;&#x7ED3;&#x679C;
    for (Product product : page){
        System.out.println(product);
    }
}</product>

5. 相似内容推荐

相似内容的推荐是给定一篇文档信息,然后向用户推荐与该文档相似的文档。通过 Elasticsearch的More like this查询接口,可以非常方便地实现基于内容的推荐,用法见以下代码: QueryBuilders.moreLikeThisQuery(new StnngQ (“WfiS”}).addLikeText(“@i®ffi”);

如果不指定字段名,则默认全部,常用在相似内容的推荐上。

QueryBuilders.moreLikeThisQuery(new String[]{“字段名”}).addLikeText(“查询值”)

4.4 范围查询

闭区间查询:QueryBuilders.rangeQuery(“字段名”).from(“值1”).to(“值2”)

开区间查询:QueryBuilders.rangeQuery(“字段名”).from(“值1”).to(“值2”).includeLower(false).includeUpper(false)

大于:QueryBuilders.rangeQuery(“字段名”).gt(“查询值”)

大于或等于:QueryBuilders.rangeQuery(“字段名”).gte(“查询值”)

小于:QueryBuilders.rangeQuery(“字段名”).lt(“查询值”)

小于或等于:QueryBuilders.rangeQuery(“字段名”).lte(“查询值”)

4.5 组合查询

组合查询是可以设置多个条件的查询方式,用来组合多个查询。有4种方式。

  • must:代表文档必须完全匹配条件,相当于and,会参与计算分值。
  • mustnot:代表必须不满足匹配条件。
  • filter:代表返回的文档必须满足filter条件,但不会参与计算分值。
  • should:代表返回的文档可能满足条件,也可能不满足条件,有多个should时满足任何一 个就可以,相当于or,可以通过minimum_should_match设置至少满足几个。

4.6 分页查询

使用NativeSearchQueryBuilder实现分页查询,用法见以下代码:

@Test
public void matchQuery(){
    NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
    nativeSearchQueryBuilder.withQuery(QueryBuilders.termQuery("name","&#x5BCC;"));
    nativeSearchQueryBuilder.withPageable(PageRequest.of(0,5));
    //&#x67E5;&#x8BE2;&#x8BCD;
    Page<product> page = productRepository.search(nativeSearchQueryBuilder.build());
    //&#x641C;&#x7D22;&#xFF0C;&#x83B7;&#x53D6;&#x7ED3;&#x679C;
    for (Product product : page){
        System.out.println(product);
    }
}</product>

如果要进行排序,只要在分页查询上构建withSort参数即可,用法见以下代码:

@Test
public void matchQuery(){
    NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
    nativeSearchQueryBuilder.withQuery(QueryBuilders.termQuery("name","&#x5BCC;"));
    nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("id").order(SortOrder.DESC));
    nativeSearchQueryBuilder.withPageable(PageRequest.of(0,5));
    //&#x67E5;&#x8BE2;&#x8BCD;
    Page<product> page = productRepository.search(nativeSearchQueryBuilder.build());
    //&#x641C;&#x7D22;&#xFF0C;&#x83B7;&#x53D6;&#x7ED3;&#x679C;
    for (Product product : page){
        System.out.println(product);
    }
}</product>

4.7 聚合查询

聚合(aggregation )是Elasticsearch的一个强大功能,可以极其方便地实现对数据的统计、分析工作。搜索是查找某些具体的文档,聚合就是对这些搜索到的文档进行统计,可以聚合出更加细致的数据。它有两个重要概念。

  • Bucket (桶/集合):满足特定条件的文档的集合,即分组。
  • Metric (指标/度量):对桶内的文档进行统计计算(最小值、最大值),简单理解就是进行运算

聚合由AggregationBuilders类来构建,它提供的静态方法见表13-3

spring boot集成Elasticsearch-SpringBoot(25)

表 13-3

具体用法见以下代码:

public List<stringterms.bucket> searchBybucket(){
    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
    queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""},null));
    //&#x6307;&#x5B9A;&#x7D22;&#x5F15;&#x7684;&#x7C7B;&#x578B;,&#x53EA;&#x5148;&#x4ECE;&#x5404;&#x5206;&#x7247;&#x4E2D;&#x67E5;&#x8BE2;&#x5339;&#x914D;&#x7684;&#x6587;&#x6863;,&#x518D;&#x91CD;&#x65B0;&#x6392;&#x540D;,&#x53D6;&#x524D;size&#x4E2A;&#x6587;&#x6863;
    queryBuilder.withSearchType(SearchType.QUERY_THEN_FETCH);
    //&#x6DFB;&#x52A0;&#x4E00;&#x4E2A;&#x65B0;&#x7684;&#x805A;&#x5408;,&#x805A;&#x5408;&#x7C7B;&#x578B;&#x4E3A;terms,&#x805A;&#x5408;&#x540D;&#x79F0;&#x4E3A;brands,&#x805A;&#x5408;&#x5B57;&#x6BB5;&#x4E3A;brand
    queryBuilder.addAggregation(AggregationBuilders.terms("brand").field("brand"));
    //&#x67E5;&#x8BE2;,&#x9700;&#x8981;&#x628A;&#x7ED3;&#x679C;&#x5F3A;&#x8F6C;&#x4E3A;Aggregatedpage&#x7C7B;&#x578B;,Aggregatedpage:&#x805A;&#x5408;&#x67E5;&#x8BE2;&#x7684;&#x7ED3;&#x679C;&#x7C7B;,&#x5B83;&#x662F;Page<t>&#x7684;&#x5B50;&#x63A5;&#x53E3;
    AggregatedPage<product> productsPage = (AggregatedPage<product>) productRepository.search(queryBuilder.build());
    //&#x4ECE;&#x7ED3;&#x679C;&#x4E2D;&#x53D6;&#x51FA;&#x540D;&#x4E3A;brands&#x7684;&#x805A;&#x5408;&#x89E3;&#x6790;
    //&#x5F3A;&#x8F6C;&#x4E3A;StringTerm&#x7C7B;&#x578B;
    StringTerms aggregations = (StringTerms) productsPage.getAggregation("brands");
    //&#x83B7;&#x53D6;&#x6876;
    List<stringterms.bucket> buckets = aggregations.getBuckets();
    //&#x904D;&#x5386;
    for (StringTerms.Bucket bucket : buckets) {
        //&#x83B7;&#x53D6;&#x6876;&#x4E2D;&#x7684;key
        System.out.println(bucket.getKey());
        //&#x83B7;&#x53D6;&#x6876;&#x4E2D;&#x7684;&#x6587;&#x6863;&#x6570;&#x91CF;
        System.out.println(bucket.getDocCount());
    }
    return buckets;
}</stringterms.bucket></product></product></t></stringterms.bucket>

还可以嵌套聚合,在聚合AggregationBuilders中使用subAggregation,用法见以下代码:

queryBuilder.addAggregation(AggregationBuilders.terms("brand").field("brand")
                            .subAggregation(AggregationBuilders.avg("price_avg").field("price"))
                            //&#x5728;&#x54C1;&#x724C;&#x805A;&#x5408;&#x6876;&#x5185;&#x8FDB;&#x884C;&#x5D4C;&#x5957;&#x805A;&#x5408;
                           );

Original: https://www.cnblogs.com/liwenruo/p/16586524.html
Author: 不惹兔子
Title: spring boot集成Elasticsearch-SpringBoot(25)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/608284/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球