elasticSearch(ES)和kibana的基本使用

本文详细描述了如何在Elasticsearch7.12.1版本中使用Docker部署并管理,以及如何在SpringBoot应用中利用RestClient进行索引库创建、删除、查询、文档CRUD操作,包括高亮查询的示例。
摘要由CSDN通过智能技术生成

本文是我在学习es的笔记,如有疏漏,敬请指出

一、创建并启动es的docker容器

#部署es,版本为7.12.1,端口号为9200

#部署es

docker run -d \
	--name es \
    -e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
    -e "discovery.type=single-node" \
    -v es-data:/usr/share/elasticsearch/data \
    -v es-plugins:/usr/share/elasticsearch/plugins \
    --privileged \
    --network es-net \
    -p 9200:9200 \
    -p 9300:9300 \
elasticsearch:7.12.1

#部署kibana,版本为7.12.1,端口号为5601

#部署kibana

docker run -d \
--name kibana \
-e ELASTICSEARCH_HOSTS=http://es:9200 \
--network=es-net \
-p 5601:5601  \
kibana:7.12.1

!两者版本必须相同

打开浏览器,进入kibana控制台

红色为虚拟机的ip黄色为设置的kibana端口号。

打开开发工具,就可以在kibana控制台内进行创建索引库、插入文档等操作

二、在Idea内利用RestClient操作索引库

docker容器必须成功部署

——添加restclient依赖

 <!--elasticSearch依赖-->
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
        </dependency>

在使用springboot时需要进行版本控制,在properties内控制版本,也正因如此上面的依赖中材不需要版本信息。

<elasticsearch.version>7.12.1</elasticsearch.version>

这样版本才不会出现错误。

——创建client对象,并设置在启动前创建并连接es(连接地址改成自己的地址

//创建client对象
    private RestHighLevelClient client;

//启动设置
@BeforeEach
    void setUp(){
        this.client = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://192.168.168.124:9200")
        ));
    }
//关闭设置
    @AfterEach
    void tearDown() throws IOException {
        this.client.close();
    }

验证初始化是否成功

@Test
    void testInit() {
        System.out.println("初始化成功");
    }

——利用RestClient创建、删除、查询(是否存在)、查询(得到的是地址)索引库

三步走:

1.创建相应的xxIndexRequest对象

2.设置(创建、删除、查询)参数

3.用client发送请求

创建时,要输入dsl语句,这里创建了一个静态变量

    //创建
    @Test
    void createHotelIndex() throws IOException {
        //创建request对象
        CreateIndexRequest request = new CreateIndexRequest("hotel");
        //准备请求参数,dsl语句
        request.source(HotelConstants.MAPPING_TEMPLATE, XContentType.JSON);
        //发送创建请求
        client.indices().create(request, RequestOptions.DEFAULT);
    }

    //删除
    @Test
    void deleteIndex() throws IOException {
        //创建request对象
        DeleteIndexRequest request = new DeleteIndexRequest();
        //删除的名称
        request.indices("hotel");
        //发送删除请求
        client.indices().delete(request, RequestOptions.DEFAULT);
    }

    //查询是否存在
    @Test
    void existIndex() throws IOException {
        //创建request对象
        GetIndexRequest request = new GetIndexRequest("hotel");
        //查询的名称
        boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
        //打印查询信息
        System.err.println(exists ? "索引库存在" : "索引库不存在");
    }

    //查询索引库


    @Test
    void getIndex() throws IOException {
        //创建request对象
        GetIndexRequest request = new GetIndexRequest("hotel");
        //发送查询请求并打印
        System.out.println(client.indices().get(request, RequestOptions.DEFAULT));
    }

三、利用RestClient操作文档(CRUD)

——C(create),新增文档

首先还是对client进行初始化

//创建client对象
    private RestHighLevelClient client;

    @Test
    void testInit() {
        System.out.println("初始化成功");
    }

    //启动设置
    @BeforeEach
    void setUp(){
        this.client = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://192.168.168.124:9200")
        ));
    }
    //关闭设置
    @AfterEach
    void tearDown() throws IOException {
        this.client.close();
    }

初始化成功之后,可以进行新增操作

以下是新增文档的方法(细节在下面有补充)

//新增文档(create-C)
    @Test
    void createDocument() throws IOException {
        //在数据库中查询数据
        HotelDoc hotelDoc = new HotelDoc(hotelService.getById(39106L));
        //创建request对象(id只能是小写,有大写会出现错误)
        IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString());
        //输入配置
        request.source(JSON.toJSONString(hotelDoc),XContentType.JSON);
        //发送请求
        client.index(request,RequestOptions.DEFAULT);
    }

1.利用mybatisPlus在数据库中根据id进行查询

首先要引入mybatisPlus的依赖

<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>

然后在application.yml文件中让mybatisPlus识别对象,并且完成数据库名到驼峰命名的转换

这里在查询完会自动导出到Hotel的POJO类

但是创建的文档中的元素跟Hotel类的元素有些许差别,因此又创建了HotelDoc的POJO类与创建文档所需要的元素类型相同,如果本来就相同可以不创建。

HotelDoc内有接受Hotel类参数并且创建对象的构造方法

接着在类名上加上@SpringBootTest注解,并自动注入IHotelService接口

到此从数据库中根据id查询并且自动装配到pojo的流程就结束了,对应第一步

2.创建request并且输入要查询的索引库名,文档名。

文档名字要小写

3.利用FastJson配置mapping

3.1引入FastJson依赖
<!--FastJson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.71</version>
        </dependency>
3.2用FastJson提供的API把对象转换为Json格式

4.发送请求

这里直接使用client的index方法,因为是创建文档,而不像之前的创建索引库

5.查询新增文档是否成功

在kibana开发工具中查询是否添加成功

查询结果

可以看到已经成功实现了新增文档的操作--查询到了!

——R(retrieve),查询文档

有了之前的依赖注入和配置,接下来只是类似的操作了,只不过使用的方法有些许不同

不过多赘述

不同:

1.R(retrieve)使用getRequest

2.需要解析结果,用了getSourceAsString方法

//查询文档(retrieve-R)
    @Test
    void retrieveDocument() throws IOException {
        //创建request对象
        GetRequest request = new GetRequest("hotel").id("39106");
        //发送请求
        GetResponse response = client.get(request, RequestOptions.DEFAULT);
        //解析并查看结果
        String sourceAsString = response.getSourceAsString();
        System.out.println(sourceAsString);
    }

——U(update),修改文档

不同:

1.U(update)使用updateRequest

2.需要准备更新的数据,使用request.doc,注意格式

——D(delete),删除文档

不同:

1.D(delete)使用deleteRequest

四、批量操作文档

不同:

1.使用bulkRequest

2.遍历了数据库得到所有数据,然后循环遍历修改格式并添加到bulkRequest中,CRUD都可以添加,添加方法就是用request.add,添加不同的操作在add方法的参数中输入不同的CRUD操作的XXrequest即可

五、使用RestClient查询文档

——MatchAll查询

match all就是查询索引库中的所有文档

在kibana中上面两种操作的结果是一样的

在idea中利用RestClient操作如下图

大体分为两步

1.创建并发送请求

与之前在操作文档时类似,不过在这里要创建的request是searchRequest(“索引名”)。在查询时主要利用官方提供的两个API(source和QueryBuilders

用source选择需要实现的查询功能

用QueryBuilders实现DQL语句的选择和编辑

需要什么从API中找就可以了

2.解析结果

可以看到在查询得到的结果中有包含总条数total、和查找结果数组hits【】等信息的hits(与前面的数组做区分),在解析时只需要一层一层地拿到

下面的查询的基本步骤都与MatchAll相同,对解析结果的代码进行了封装(getResult)下面只指出主要的不同点

——Match查询

match则是根据输入的query条件进行查询

对应的RestClient操作如下图

不同:

1.QueryBuilders的使用不同,使用了matchQuery的API并指定了要查询的词条和内容

——term、range、boolean查询

term查询是全局精确查询,查询结果必须跟输入的信息一致

range查询是范围查询

boolean查询是条件判断查询,有must、mustNot、filter、should等条件,其中还有一些与评分机制有关,感兴趣的可以自行查找

不同:

1.QueryBuilders的使用不同,创建了一个BoolQueryBuilder并编辑了要查询的词条和内容

2.使用链式编程在编辑查询条件时加入了term和range查询,意思是:城市必须在上海,价格在300以下

——分页和排序

分页使用的是from(第几页)和size(每页的大小),排序使用sort指定要排序的词条和升降序

不同:

1.这里不再重点关注查询,而是对source的操作,这里使用了MatchAll

2.使用链式编程在编辑source时加入了sort和from、size,意思是:对价格进行升序排序,从当前页(3)开始,每页有7条数据

——高亮设置

不同:

1.创建了HighlightBuilder这里两种创建方法是一样的

new HighlightBuilder()和SearchSourceBuilder.highlight()

2.对source的操作(使用的是highlighter),首先进行一次全文匹配Match查询,然后配置highlighter,最后使用链式编程进行高亮设置,意思是:“city”字段高亮,且不需要与查询字段匹配

3.结果解析过程不同

解析过程添加了以下获取、判断和覆盖的过程

如下图,可以看到在hit【】数组的元素hit中source和highlight是平级的

根据之前的解析过程,在循环中可以直接用 hit.getHighlightFields() 获取高亮相关的信息,得到的是一个Map集合,然后获取集合中的高亮字段并对原字段进行覆盖

运行后的结果可以看到确实进行了覆盖

——代码

package cn.itcast.hotel;

import cn.itcast.hotel.pojo.HotelDoc;
import com.alibaba.fastjson.JSON;
import org.apache.http.HttpHost;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.Map;

public class HotelSearchTest {
    //创建client对象
    private RestHighLevelClient client;

    @Test
    void testInit() {
        System.out.println("初始化成功");
    }

    //启动设置
    @BeforeEach
    void setUp() {
        this.client = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://192.168.168.124:9200")
        ));
    }

    //关闭设置
    @AfterEach
    void tearDown() throws IOException {
        this.client.close();
    }

    //MatchAll
    @Test
    void testMatchAll() throws IOException {
        //创建请求
        SearchRequest request = new SearchRequest("hotel");
        //编辑请求中的dsl语句
        request.source().query(QueryBuilders.matchAllQuery());
        //发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //解析并打印结果
        getResult(response);
    }

    //Match
    @Test
    void testMatch() throws IOException {
        //创建请求
        SearchRequest request = new SearchRequest("hotel");
        //编辑请求中的dsl语句
        request.source().query(QueryBuilders.matchQuery("city", "上海"));
        //发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //解析并打印结果
        getResult(response);
    }

    //term、range、boolean查询
    @Test
    void testTRB() throws IOException {
        //创建请求
        SearchRequest request = new SearchRequest("hotel");
        //编辑请求中的dsl语句
            //创建一个BoolQueryBuilder
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
            //编辑BoolQueryBuilder
        boolQuery.must(QueryBuilders.termQuery("city","上海"))
                .filter(QueryBuilders.rangeQuery("price").lte(300));
            //传输给source
        request.source().query(boolQuery);
        //发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //解析并打印结果
        getResult(response);
    }

    //PageAndSort
    @Test
    void testPageAndSort() throws IOException {
        //当前页数和每页的大小
        int page = 3, size = 7;
        //创建请求
        SearchRequest request = new SearchRequest("hotel");
        //编辑请求中的dsl语句
        request.source().query(QueryBuilders.matchAllQuery())
                .sort("price", SortOrder.ASC)
                .from((page - 1) * size)
                .size(size);
        //发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //解析并打印结果
        getResult(response);
    }

    //HighLight
    @Test
    void testHigh() throws IOException {
        //创建请求
        SearchRequest request = new SearchRequest("hotel");
        //编辑请求中的dsl语句
        request.source().query(QueryBuilders.matchQuery("city", "上海"))
                .highlighter(SearchSourceBuilder.highlight()
                        .field("city")
                        .requireFieldMatch(false));
        //发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //解析并打印结果
        getResult(response);
    }

    //解析
    private void getResult(SearchResponse response) {
        //得到hits数组
        SearchHit[] hits = response.getHits().getHits();
        //遍历得到每条hit
        for (SearchHit hit : hits) {
            //得到每条hit的source
            String sourceFromHit = hit.getSourceAsString();
            //利用Fastjson反序列化,输入要反序列化的对象的class字节码
            HotelDoc parsed2HotelDoc = JSON.parseObject(sourceFromHit, HotelDoc.class);
            //获取高亮结果的集合
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            //判断集合是否为空,不为空则执行高亮覆盖
            if (!CollectionUtils.isEmpty(highlightFields)) {
                //根据搜索内容(city对应 键)获取高亮结果(highlightField对应 值)
                HighlightField highlightField = highlightFields.get("city");
                //判断高亮结果是否空
                if(highlightField != null){
                    //得到高亮的字段
                    String highlightSection = highlightField.getFragments()[0].string();
                    //覆盖非高亮结果
                    parsed2HotelDoc.setCity(highlightSection);
                }
            }
            //打印
            System.out.println(parsed2HotelDoc);
        }
    }
}

如有纰漏,敬请指出

  • 10
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值