ElasticSearch

1.ES简介
2.es倒排索引
3.es的初步使用
4.索引库
5.java代码操作es
6.添加文档-数据
7.查询语法
8.java代码实现
9.开发中的使用
10.分组 / 统计(平均值/最大值/…)
11.java代码实现
12.数据聚合 -> 点击选项查询,其他选项存在数据久显示该选项
13.输入内容自动补全
14.sql与es 数据同步
15.集群

es简介

在这里插入图片描述

在这里插入图片描述

倒排索引

根据搜索条件进行分词,得到分词结果去词条列表进行查询,获取文档ID,根据文档集对应的ID,查询出对应的文档.

  • 介绍
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

与mysql的对比
在这里插入图片描述

总结

在这里插入图片描述

安装es - kibana

## 1.1.创建网络

因为我们还需要部署kibana容器,因此需要让es和kibana容器互联。这里先创建一个网络:

```sh
docker network create es-net

1.2.加载镜像

这里我们采用elasticsearch的7.12.1版本的镜像,这个镜像体积非常大,接近1G。不建议大家自己pull。

课前资料提供了镜像的tar包:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QqN8f2Ae-1671012481661)(assets/image-20210510165308064.png)]

大家将其上传到虚拟机中,然后运行命令加载即可:

# 导入数据
docker load -i es.tar

同理还有kibana的tar包也需要这样做。

1.3.运行

运行docker命令,部署单点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

命令解释:

  • -e "cluster.name=es-docker-cluster":设置集群名称
  • -e "http.host=0.0.0.0":监听的地址,可以外网访问
  • -e "ES_JAVA_OPTS=-Xms512m -Xmx512m":内存大小
  • -e "discovery.type=single-node":非集群模式
  • -v es-data:/usr/share/elasticsearch/data:挂载逻辑卷,绑定es的数据目录
  • -v es-logs:/usr/share/elasticsearch/logs:挂载逻辑卷,绑定es的日志目录
  • -v es-plugins:/usr/share/elasticsearch/plugins:挂载逻辑卷,绑定es的插件目录
  • --privileged:授予逻辑卷访问权
  • --network es-net :加入一个名为es-net的网络中
  • -p 9200:9200:端口映射配置

在浏览器中输入:http://192.168.150.101:9200 即可看到elasticsearch的响应结果:

2.部署kibana

kibana可以给我们提供一个elasticsearch的可视化界面,便于我们学习。

2.1.部署

运行docker命令,部署kibana

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

es初步使用

在这里插入图片描述

使用LK分词器

在这里插入图片描述

新兴的词语要用扩展词条

在这里插入图片描述

停用词词典

在这里插入图片描述

索引库

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

文档的增删改查

在这里插入图片描述

在这里插入图片描述

java操作es

  • 初始化操作
    在这里插入图片描述
  • 关闭操作
    在这里插入图片描述

新增/删除索引库

在这里插入图片描述

    @Test
    public void insert() throws IOException {
        // 1. 本次向es发送请求为的是创建heima索引库
        CreateIndexRequest request = new CreateIndexRequest("heima");
        // 2. 发送es请求,接收响应结果
        // client.indices() :通过客户端创建索引库
        // create(request, RequestOptions.DEFAULT) 参数1:请求创建的参数  ,  请求方式-固定
        CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
        // 3.处理请求结果
        boolean flag = response.isAcknowledged();
        System.out.println("当前请求的结果为:"+flag);

    }

    @Test
    public void Delete() throws IOException {
        // 1. 本次向es发送请求为的是创建heima索引库
        DeleteIndexRequest request = new DeleteIndexRequest("heima");
        // 2. 删除索引库
        AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);
        // 3.处理请求结果
        boolean flag = delete.isAcknowledged();
        System.out.println("当前删除的结果为    :"+flag);

    }

查看索引库是否存在/结构

在这里插入图片描述

    // 判断API是否存在
    @Test
    public void exists() throws IOException {
        // 1. 本次向es发送请求为的是创建heima索引库
        GetIndexRequest request = new GetIndexRequest("heima");
        // 2. 查看索引库是否存在
        boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
        // 3.处理请求结果
        if (exists){
            System.out.println("当前所有存在");
        }else {
            System.out.println("当前索引不存在");
        }
    }

    // 查看索引库结果
    @Test
    public void get() throws IOException {
        // 1. 本次向es发送请求为的是创建heima索引库
        GetIndexRequest request = new GetIndexRequest("heima");
        // 2. 查看索引库结果
        GetIndexResponse response = client.indices().get(request, RequestOptions.DEFAULT);
        // 3.处理请求结果
        Map<String, MappingMetadata> map = response.getMappings();
        System.out.println(map);
        MappingMetadata heima = map.get("heima");
        Map<String, Object> sourceAsMap = heima.getSourceAsMap();
        System.out.println(sourceAsMap);
    }

添加文档 / 数据

import org.apache.http.HttpHost;
import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

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

@SpringBootTest
public class HelloTest {
    

    private RestHighLevelClient client;

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


    // 添加文档数据
    @Test
    public void indexs() throws IOException {
        IndexRequest request = new IndexRequest("heima");
        request.id("1");
        String docJson = "{\n" +
                "  \"info\":\"黑马\",\n" +
                "  \"email\":\"zy@qq.com\",\n" +
                "  \"name\":{\n" +
                "    \"firstName\":\"云\",\n" +
                "    \"lastName\":\"找\"\n" +
                "  }\n" +
                "}";
        request.source(docJson , XContentType.JSON);
        // 2.发送请求给es数据,接收响应数据
        IndexResponse response = client.index(request, RequestOptions.DEFAULT);
        // 3.处理响应结果
        DocWriteResponse.Result result = response.getResult();
        System.out.println("添加数据"+result);
    }

    // 查看文档数据
    @Test
    public void Query() throws IOException {
        GetRequest request = new GetRequest("heima","1");
        // 2.发送请求给es数据,接收响应数据
        GetResponse documentFields = client.get(request, RequestOptions.DEFAULT);
        // 3.处理响应结果
        String sourceAsString = documentFields.getSourceAsString();
        System.out.println(sourceAsString);
    }

    // 修改
    @Test
    public void Update1() throws IOException {
        UpdateRequest request = new UpdateRequest("heima","1");
        // 2.发送请求给es数据,接收响应数据
        request.doc(
                "email","66666666666@qq.com"
        );
        UpdateResponse update = client.update(request, RequestOptions.DEFAULT);
        // 3.获取请求结果
        DocWriteResponse.Result result = update.getResult();
        System.out.println(result);
    }

    // 删除
    @Test
    public void delete() throws IOException {
        DeleteRequest request = new DeleteRequest("heima" , "1");
        DeleteResponse delete = client.delete(request, RequestOptions.DEFAULT);
        DocWriteResponse.Result result = delete.getResult();
        System.out.println("删除的结果为"+result);

    }

    @AfterEach
    void tearDown() throws IOException {
        this.client.close();
    }
    
}

SQL添加es

在这里插入图片描述
在这里插入图片描述

import cn.itcast.hotel.constants.HotelConstants;
import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.service.IHotelService;
import com.alibaba.fastjson.JSON;
import net.minidev.json.JSONUtil;
import org.apache.http.HttpHost;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.rest.RestStatus;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;
import java.util.List;

@SpringBootTest
public class HotelTest {

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

    @Autowired
    private IHotelService iHotelService ;


    private RestHighLevelClient client = null;

    // 创建索引库
    @Test
    public void  test03() throws IOException {
        // 1. 本次向es发送请求为的是创建heima索引库
        CreateIndexRequest request = new CreateIndexRequest("hotel");
        request.mapping(HotelConstants.MAPPING_TEMPLATE, XContentType.JSON);
        // 2. 发送es请求,接收响应结
        CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
        boolean fragment = response.isAcknowledged();
        if (fragment){
            System.out.println("操作成功");
        }
    }

    // SQL数据添加到es中
    @Test
    public void test01() throws IOException {
        Hotel hotel = iHotelService.findByid(36934l);
        // 将数据修改为es的数据格式
        HotelDoc hotelDoc = new HotelDoc(hotel);
        // 将java数据修改为json
        String hotelJson = JSON.toJSONString(hotelDoc);
        System.out.println(hotelJson);
        // 1. 创建添加语义对象
        IndexRequest request = new IndexRequest("hotel");
        request.id("36934");
        // 设置添加的文档数据
        request.source(hotelJson , XContentType.JSON);
        // 发送给es
        IndexResponse response = client.index(request, RequestOptions.DEFAULT);
        DocWriteResponse.Result result = response.getResult();
        System.out.println(result);
    }

    /**
     * 向es中,批量添加数据 / 将数据库中的数据全部添加到es中
     * @throws IOException
     */
    @Test
    public void bulk() throws IOException {
        // 从mysql中查询所有的数据
        List<Hotel> all = iHotelService.findAll();
        // 批量创建请求的语义对象
        BulkRequest bulkRequest = new BulkRequest("hotel");

        // 处理对象并转化
        for (Hotel hotel : all ){
            HotelDoc hotelDoc = new HotelDoc(hotel);
            String hotelJson = JSON.toJSONString(hotelDoc);
            // 1. 创建添加语义对象
            IndexRequest request = new IndexRequest("hotel");
            request.id(hotel.getId()+" ");
            // 设置添加的文档数据
            request.source(hotelJson , XContentType.JSON);
            bulkRequest.add(request);
        }
        BulkResponse responses = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        RestStatus status = responses.status();
        System.out.println(responses +"  " + status);
    }

    @AfterEach
    void tearDown() throws IOException {
        this.client.close();
    }
}

查询语法

在这里插入图片描述

ES查询语句

在这里插入图片描述

全文检索查询 where or

在这里插入图片描述

#match   分词查询,匹配一个字段
GET /hotel/_search
{
  "query": {
    "match": {
      "name": "上海"
    }
  },
  "size": 200
}
#math  查询所有字段中包含xx的数据
GET /hotel/_search
{
  "query": {
  "match": {
    "all": "上海"
  }
  },
  "size": 200
}

#multi_match   分词查询,匹配多个字段
GET /hotel/_search
{
  "query": {
    "multi_match": {
      "query": "上海",
      "fields": ["name" ,"brand"]
    }
  },
  "size": 200
}

精确查询 (查询条件不分词 between and )

在这里插入图片描述

#范围查询   100 - 200   
# gt > gte >=  lt < lt <=  
GET /hotel/_search
{
  "query": {
  "range": {
    "price": {
      "gte": 100,
      "lte": 200
    }
  }
  }
}

GET /hotel/_search
{
  "query": {
  "ids": {
    "price": [123 , 124]
  }
  }
}

地理坐标查询 (根据经纬度查询)

在这里插入图片描述

#地理坐标查询  矩形范围查询
GET /hotel/_search
{
  "query": {
  "geo_bounding_box": {
    "location": {
     "top_left": {
       "lat": 31.1,
       "lon": 121.5
     },
     "bottom_right": {
       "lat": 30.9,
       "lon": 121.7
     }
    }
  }
  }
}
#附近查询 geo_distance 查询  圓心坐標+方圓多少公里
GET /hotel/_search
{
  "query": {
    "geo_distance": {
      "distance": "15km",
      "location": "31.21,121.5" 
  }
  }
}

复合查询

在这里插入图片描述

#在搜索时,es将结果自动排序,根据分值进行排序
GET /hotel/_search
{
  "query": {
    "function_score": {
      "query": { 
        
      "match": {
        "name": "如家酒店"
      }
      }, 
      "functions": [ 
        {
          "filter": { 
            "term": {
              "brand": "如家"
            }
          },
          "weight": 2 
        }
      ],
      "boost_mode": "sum" 
    }
  }
}
#在搜索时,es将结果自动排序,根据分值进行排序
GET /hotel/_search
{
  "query": {
    "function_score": {
      "query": { 
        
      "match": {
        "name": "如家酒店"
      }
      }, 
      "functions": [ 
        {
          "filter": { 
            "term": {
              "id": "2359697"
            }
          },
          "weight": 200
        }
      ],
      "boost_mode": "multiply" 
    }
  }
}

布尔查询 多条件组合

在这里插入图片描述

#布尔查询
GET /hotel/_search
{
  "query": {
    "bool": {
      "must": [
        {"term": {"city": "上海" }}
      ],
      "should": [
        {"term": {"brand": "皇冠假日" }},
        {"term": {"brand": "华美达" }}
      ],
      "must_not": [
        { "range": { "price": { "lte": 500 } }}
      ],
      "filter": [
        { "range": {"score": { "gte": 45 } }}
      ]
    }
  }
}

排序

在这里插入图片描述

# 排序  默认为分值排序  , 如果设置了排序字段,则不再计较分值
# 根据第一个字段进行排序,如果结果一样,根据第二个字段进行排序
GET /hotel/_search
{
  "query": {
    "term": {
      "brand": "如家"
    }
  },
  "sort": [
    {
      "price": "asc"
      },
      {
        "score":"asc"
      }
  ]
}

GET /hotel/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "_geo_distance" : {
          "location": "31.034661 , 121.612282", 
          "order" : "asc", 
          "unit" : "km" 
      }
    }
  ]
}

分页

在这里插入图片描述

随机翻页页码

在这里插入图片描述

在这里插入图片描述

#分页查询  from : 当前页码-1    size:每页显示条数
GET /hotel/_search
{
  "query": {
    "term": {
      "brand": "如家" 
    }
  },
  "from": 0 ,
  "size": 20
}

手机翻页

在这里插入图片描述

高亮搜索

在这里插入图片描述
在这里插入图片描述

java代码实现

在这里插入图片描述

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.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
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 java.io.IOException;

public class esTset {



        private RestHighLevelClient client;

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



        @Test //  查询所有
        public void EsTest() throws IOException {
            // 1.准备Request
            SearchRequest request = new SearchRequest("hotel");
            // 2.准备DSL
            request.source().query(QueryBuilders.matchAllQuery());
            // 3.发送请求
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);

            // 4.解析响应
            handleResponse(response);
        }

        // 解析结果
    private void handleResponse(SearchResponse response) {
        // 4.解析响应
        SearchHits searchHits = response.getHits();
        // 4.1.获取总条数
        long total = searchHits.getTotalHits().value;
        System.out.println("共搜索到" + total + "条数据");
        // 4.2.文档数组
        SearchHit[] hits = searchHits.getHits();
        // 4.3.遍历
        for (SearchHit hit : hits) {
            // 获取文档source
            String json = hit.getSourceAsString();
            // 反序列化   将json转化为对象
            HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
            System.out.println("hotelDoc = " + hotelDoc);
        }
    }


    @Test //  分词查询
    public void EsTest1() throws IOException {
        // 1.准备Request
        SearchRequest request = new SearchRequest("hotel");
        // 2.准备DSL
        request.source().query(QueryBuilders.matchQuery("name" , "上海外滩"));
        // 3.发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        // 4.解析响应
        handleResponse(response);
    }

    @Test //  分词查询多个字段
    public void EsTest2() throws IOException {
        // 1.准备Request
        SearchRequest request = new SearchRequest("hotel");
        // 2.准备DSL
        request.source().query(QueryBuilders.multiMatchQuery("上海外滩" , "name" , "brand"));
        // 3.发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        // 4.解析响应
        handleResponse(response);
    }

    @Test // 范围查询
    public void EsTest3() throws IOException {
        // 1.准备Request
        SearchRequest request = new SearchRequest("hotel");
        // 2.准备DSL
        request.source().query(QueryBuilders.rangeQuery("price").gte(100).lte(200));
        // 3.发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 4.解析响应
        handleResponse(response);
    }


    @Test // 词条查询  // 查询内容作为一个整体进行查询
    public void EsTest4() throws IOException {
        // 1.准备Request
        SearchRequest request = new SearchRequest("hotel");
        // 2.准备DSL
        request.source().query(QueryBuilders.termQuery("city" , "北京"));
        // 3.发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 4.解析响应
        handleResponse(response);
    }

    // 布尔查询
    @Test
    public void EsTest5() throws IOException {
        // 1.准备Request
        SearchRequest request = new SearchRequest("hotel");
        // 2.准备DSL
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.must(QueryBuilders.termQuery("city" , "上海"));
        boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(2000));
//        boolQueryBuilder.filter(QueryBuilders.termQuery("city","上海"));
        request.source().query(boolQueryBuilder);
        // 3.发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 4.解析响应
        handleResponse(response);
    }

    //排序喝分页
    @Test
    public void EsTest6() throws IOException {
        // 1.准备Request
        SearchRequest request = new SearchRequest("hotel");
        // 2.准备DSL
        request.source().query(QueryBuilders.termQuery("city" , "北京"));
        //  todo:排序
        request.source().sort("price" , SortOrder.ASC);
        //  todo:分页
        request.source().from(0);
        request.source().size(5);
        // 3.发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 4.解析响应
        handleResponse(response);
    }

    // 高亮排序
    @Test
    public void EsTest7() throws IOException {
        // 1.准备Request
        SearchRequest request = new SearchRequest("hotel");
       //  2.构建条件
        request.source().query(QueryBuilders.matchQuery("all","如家酒店"));
        // todo: 高亮查询
        request.source().highlighter(
                new HighlightBuilder()
                .field("name")
                .requireFieldMatch(false)
        );
        // 3.发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 4.解析响应
        handleResponses(response);
    }

    // 解析高亮结果数据
    private void handleResponses(SearchResponse response) {
        // 4.解析响应
        SearchHits searchHits = response.getHits();
        // 4.1.获取总条数
        long total = searchHits.getTotalHits().value;
        System.out.println("共搜索到" + total + "条数据");
        // 4.2.文档数组
        SearchHit[] hits = searchHits.getHits();
        // 4.3.遍历
        for (SearchHit dohit : hits) {
            // todo: 解析高亮
            HighlightField highlightField = dohit.getHighlightFields().get("name");
           String name = " " ;
           if (highlightField!=null){
               name = highlightField.getFragments()[0].string();
               System.out.println(name);
           }
        }
    }



    @AfterEach
        void tearDown() throws IOException {
            this.client.close();
        }
}

查询数据的全部方法

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

        @Test //  查询所有
        public void EsTest() throws IOException {
            // 1.准备Request
            SearchRequest request = new SearchRequest("hotel");
            // 2.查询所有
            request.source().query(QueryBuilders.matchAllQuery());

            // 2.分词查询
            request.source().query(QueryBuilders.matchQuery("name" , "上海外滩"));

            // 3.范围查询
            request.source().query(QueryBuilders.rangeQuery("price").gte(100).lte(200));

            // 4. 词条查询查询内容作为一个整体进行查询
            request.source().query(QueryBuilders.termQuery("city" , "北京"));

            // 5. 布尔查询
            BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
            boolQueryBuilder.must(QueryBuilders.termQuery("city" , "上海"));
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(2000));
            request.source().query(boolQueryBuilder);
            
            //  todo:排序
            request.source().sort("price" , SortOrder.ASC);
            //  todo:分页
            request.source().from(0);
            request.source().size(5);
            
            // 6. 高亮查询
            //  2.构建条件
            request.source().query(QueryBuilders.matchQuery("all","如家酒店"));
            // todo: 高亮查询
            request.source().highlighter(
                    new HighlightBuilder()
                            .field("name")
                            .requireFieldMatch(false)
            );

            // 3.发送请求
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);

            // 4.解析响应
            handleResponse(response);
        }

开发中的使用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述查询的是这个:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

    // 创建es客户端对象,存入ioc容器中
    @Bean
    public RestHighLevelClient RestHighLevelClient(){
        RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://192.168.136.131:9200")
        ));
        return client ;
    }
    --------------------------------------------------------------------------------------------
     @Autowired
    private RestHighLevelClient client ;


    @Override
    public PageResult search(RequestParams params) throws IOException {
        PageResult pageResult = new PageResult();
        Integer page = params.getPage();
        Integer size = params.getSize();


        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();

        // 1.准备Request
        SearchRequest request = new SearchRequest("hotel");

        if (params.getKey()==null || "".equals(params.getKey())){
            // 用户没有输入 , 构建查询所有的DSL
            boolQueryBuilder.must(QueryBuilders.matchAllQuery());
        }else {
            // 用户输入了,使用分词查询
            boolQueryBuilder.must(QueryBuilders.matchQuery("all" , params.getKey()));
        }

        // 构造查询方法
       if (params.getCity()!= null && !params.getCity().equals("")){
           boolQueryBuilder.filter(QueryBuilders.termQuery("city" , params.getCity() ));
       }

        if (params.getBrand()!= null && !params.getBrand().equals("")){
            boolQueryBuilder.filter(QueryBuilders.termQuery("brand" , params.getBrand() ));
        }

        if (params.getStarName()!= null && !params.getStarName().equals("")){
            boolQueryBuilder.filter(QueryBuilders.termQuery("starName" , params.getStarName() ));
        }

        if (params.getMinPrice() !=null && params.getMaxPrice()!=null){
            boolQueryBuilder.filter(QueryBuilders
            .rangeQuery("price")
            .gte(params.getMinPrice())
            .lte(params.getMaxPrice()));
        }

        // 2.算分控制
        FunctionScoreQueryBuilder functionScoreQuery =
                QueryBuilders.functionScoreQuery(
                        // 原始查询,相关性算分的查询
                        boolQueryBuilder ,
                        // function score的数组
                        new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                                // 其中的一个function score 元素
                                new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                                        // 过滤条件
                                        QueryBuilders.termQuery("isAD", true),
                                        // 算分函数
                                        ScoreFunctionBuilders.weightFactorFunction(100000)
                                )
                        });

        // 放布尔查询条件放入request中
        request.source().query(functionScoreQuery);

        // 地理坐标  排序
        String location = params.getLocation();
        if (location != null && !location.equals("")) {
            request.source().sort(SortBuilders
                    .geoDistanceSort("location", new GeoPoint(location))
                    .order(SortOrder.ASC)
                    .unit(DistanceUnit.KILOMETERS)
            );
        }

        //  todo:分页
        request.source().from( (page - 1) * size );
        request.source().size(10);

        // 3.发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 4.解析响应
        SearchHits searchHits = response.getHits();
        // 4.1.获取总条数
        long total = searchHits.getTotalHits().value;
        pageResult.setTotal(total);
        System.out.println("共搜索到" + total + "条数据");
        // 4.2.文档数组
        SearchHit[] hits = searchHits.getHits();
        // 4.3.遍历
        List<HotelDoc> list = new ArrayList<>();
        for (SearchHit hit : hits) {
            // 获取文档source
            String json = hit.getSourceAsString();
            // 反序列化   将json转化为对象
            HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);

            // 取出距离值
            Object[] sortValues = hit.getSortValues();
            if (sortValues.length > 0){
                hotelDoc.setDistance(sortValues[0]);
            }

            list.add(hotelDoc);
        }
        pageResult.setHotels(list);
        return pageResult ;
    }

自动补全

聚合

在这里插入图片描述

分组

多个分组

在这里插入图片描述

#聚合函数    根据酒店品牌进行分组
GET /hotel/_search
{
  "size": 0,    #不需要展示命中的文档数据
  "aggs": {   # 固定属性 , 聚合内容
    "brandName": {   #自定义聚合名称,根据名称获取集合的结果
      "terms": {  #根据词条进行分桶
        "field": "brand",   # 分桶字段
        "size": 20   # 展示多少个桶
      }
    }
  }
}


# 聚合结果
GET /hotel/_search
{
  "size": 0,   
  "aggs": {
    "brandName": {
      "terms": {
        "field": "brand", 
        "order":{
          "_count": "asc"
        },
        "size": 20
      }
    },
    "dizi": {
      "terms": {
        "field": "city",
        "size": 10
      }
    }
  }
}

多次分组

在这里插入图片描述

GET /hotel/_search
{
  "size": 0,

  "aggs": {
    "brandName": {
      "terms": {
        "field": "brand", 
        "size": 20
      },
    "aggs": {
      "cityName": {
      "terms": {
        "field": "city", 
        "size": 10
    }
    }
    }
    }
    }
    }

限定查询范围分组

在这里插入图片描述

# 限定查询范围
GET /hotel/_search
{
  "size": 0,
  "query": {
    "term": {
      "city": "上海"
    }
  }, 
  "aggs": {
    "brandName": {
      "terms": {
        "field": "brand", 
        "order":{
          "_count": "asc"
        },
        "size": 20
      }
    }
  }
} 

对当前数据进行分组在分组后,对分组后的数据进行求和

在这里插入图片描述

GET /hotel/_search
{
  "size": 0,

  "aggs": {
    "brandName": {
      "terms": {
        "field": "brand", 
        "size": 20
      },
    "aggs": {
      "cityName": {
      "terms": {
        "field": "city", 
        "size": 10
    },
    "aggs": {
        "price_status_name": {
          "avg": {
            "field": "price"
          }
        }
    }
    }
    }
    }
    }
    }

最大值 / 最小值 / 平均值 / 求和 -> 必须要带查询

srats:统计所有
在这里插入图片描述

# 先对数据进行分组,对组内的数据进行度量 
GET /hotel/_search
{
  "size": 0,
  "aggs": {
    "brandName": {
      "terms": {
        "field": "brand", 
        "order":{
          "price_score_name.max": "desc"
        },
        "size": 20
      },
      "aggs": {
        "price_status_name": {
          "stats": {
            "field": "price"
          }
        },
        "price_score_name": {
          "stats": {
            "field": "score"
          }
        }
      }
    }
  }
}

java代码实现分组 / 平均值…

分组的代码实现
在这里插入图片描述

import java.io.IOException;
import java.util.List;

public class Dotets {

    private RestHighLevelClient client;

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


    @Test
    public void test02() throws IOException {
        // 1.准备Request
        SearchRequest request = new SearchRequest("hotel");
        request.source().size(0);
        // 2. 设置分组数据
        request.source().aggregation(
                AggregationBuilders.terms("brandName")
                .field("brand")
                .size(10)
        );
        // 城市分组
        request.source().aggregation(
                AggregationBuilders.terms("citydName")
                        .field("city")
                        .size(10)
        );
        // 3. 发送请求给es,并接收结果
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        handleResponse(response , "brandName");
        System.out.println("---------------------------------------------");
        handleResponse(response , "citydName");

    }

    private void handleResponse(SearchResponse response , String name) {
        // 4. 解析聚合结果
        Aggregations aggregations = response.getAggregations();
        Terms terms = aggregations.get(name);

        List<? extends Terms.Bucket> buckets = terms.getBuckets();

        for (Terms.Bucket bucket : buckets){
            Object key = bucket.getKey();
            long docCount = bucket.getDocCount();
            System.out.println(key +" "+ docCount);
        }
    }





    @AfterEach
    void tearDown() throws IOException {
        this.client.close();
    }
}

查询

在这里插入图片描述在这里插入图片描述
在这里插入图片描述



    @Autowired
    private RestHighLevelClient client ;
    
    /**
     *  聚合查询酒店的星级
     * @param params
     * @return
     */
    @Override
    public Map<String, List<String>> getFilters(RequestParams params) throws IOException {
        // 1.准备Request
        SearchRequest request = new SearchRequest("hotel");
        buildBasicQuery(params , request);
        request.source().size(0);
        // 2. 设置分组数据
        request.source().aggregation(
                AggregationBuilders.terms("brandAgg")
                        .field("brand")
                        .size(100)
        );
        // 城市分组
        request.source().aggregation(
                AggregationBuilders.terms("cityAgg")
                        .field("city")
                        .size(100)
        );
        //
        request.source().aggregation(AggregationBuilders
        .terms("starAgg")
        .field("starName")
        .size(100));
        // 3. 发送请求给es,并接收结果
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        // 4.解析结果
        Aggregations aggregations = response.getAggregations();

        List<String> list1 = handleResponse(aggregations, "brandAgg");
        List<String> list2 = handleResponse(aggregations, "cityAgg");
        List<String> list3 = handleResponse(aggregations, "starAgg");

        Map<String, List<String>> map = new HashMap<>(3);
        map.put("brand" , list1);
        map.put("city" , list2);
        map.put("starName" , list3);

        return map ;
    }
    private List<String> handleResponse(Aggregations aggregations , String name) {
        // 4. 解析聚合结果

        Terms terms = aggregations.get(name);

        List<String> list = new ArrayList<>();

        List<? extends Terms.Bucket> buckets = terms.getBuckets();

        if (buckets != null){
            for (Terms.Bucket bucket : buckets){
                String key = bucket.getKeyAsString();
                list.add(key);
            }
        }

        return list ;

    }

    private void buildBasicQuery(RequestParams params, SearchRequest request) {
        // 1.准备Boolean查询
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        // 1.1.关键字搜索,match查询,放到must中
        String key = params.getKey();
        if (StringUtils.isNotBlank(key)) {
            // 不为空,根据关键字查询
            boolQuery.must(QueryBuilders.matchQuery("all", key));
        } else {
            // 为空,查询所有
            boolQuery.must(QueryBuilders.matchAllQuery());
        }

        // 1.2.品牌
        String brand = params.getBrand();
        if (StringUtils.isNotBlank(brand)) {
            boolQuery.filter(QueryBuilders.termQuery("brand", brand));
        }
        // 1.3.城市
        String city = params.getCity();
        if (StringUtils.isNotBlank(city)) {
            boolQuery.filter(QueryBuilders.termQuery("city", city));
        }
        // 1.4.星级
        String starName = params.getStarName();
        if (StringUtils.isNotBlank(starName)) {
            boolQuery.filter(QueryBuilders.termQuery("starName", starName));
        }
        // 1.5.价格范围
        Integer minPrice = params.getMinPrice();
        Integer maxPrice = params.getMaxPrice();
        if (minPrice != null && maxPrice != null) {
            maxPrice = maxPrice == 0 ? Integer.MAX_VALUE : maxPrice;
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(minPrice).lte(maxPrice));
        }

        // 2.算分函数查询
        FunctionScoreQueryBuilder functionScoreQuery = QueryBuilders.functionScoreQuery(
                boolQuery, // 原始查询,boolQuery
                new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{ // function数组
                        new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                                QueryBuilders.termQuery("isAD", true), // 过滤条件
                                ScoreFunctionBuilders.weightFactorFunction(10) // 算分函数
                        )
                }
        );

        // 3.设置查询条件
        request.source().query(functionScoreQuery);
    }

自动补全

拼音分词器
在这里插入图片描述
自动补全
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


    // 自动补全
    @Override
    public List<String> getsuggetions(String prefix) {
        try {
            // 1.准备Request
            SearchRequest request = new SearchRequest("hotel");
            // 2.准备DSL
            request.source().suggest(new SuggestBuilder().addSuggestion(
                    "suggestions",  // 自定义补全字段名称
                    SuggestBuilders.completionSuggestion("suggestion")  // 补全字段
                            .prefix(prefix)  // 补全字段的关键字
                            .skipDuplicates(true)  // 跳过重复的
                            .size(10)  // 获取前10条结果
            ));
            // 3.发起请求
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            // 4.解析结果
            Suggest suggest = response.getSuggest();
            // 4.1.根据补全查询名称,获取补全结果
            CompletionSuggestion suggestions = suggest.getSuggestion("suggestions");
            // 4.2.获取options
            List<CompletionSuggestion.Entry.Option> options = suggestions.getOptions();
            // 4.3.遍历
            List<String> list = new ArrayList<>(options.size());
            for (CompletionSuggestion.Entry.Option option : options) {
                String text = option.getText().toString();
                list.add(text);
            }
            return list;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

数据同步

在这里插入图片描述

spring:
  rabbitmq:
    host: 192.168.136.131
    port: 5672
    virtual-host: /
    username: xiaowang
    password: 123321
  • 解决方式
  • 1.同步调用,在操作sql完成新增/修改/删除操作时,对es完成同样的操作

在这里插入图片描述

    1. 利用rabbq发送消息,当新增成功后,生产者向rabbq发送消息,
      生产者:
      在这里插入图片描述
      消费者:
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

es集群

集群下的每一台服务器叫做节点,多个节点组成集群,先将海量数据进行分片,在对数据进行分配

  • 解决海量数据存储
  • 答:将索引拆分为每一片存储到不同的服务器上
  • 如果服务器宕机,单点故障
  • 答:分片构建副本
    在这里插入图片描述
    节点划分:
    在这里插入图片描述
    在这里插入图片描述节点的作用
    在这里插入图片描述

脑裂问题

在这里插入图片描述
在es7.0之后修复了这个问题,添加了hash运算,当主节点发生为问题后,副本节点进行投票(当前集群+1)%2 的方法进行推选主节点,当宕机的主节点修复后,变为从节点

故障转移 / 动态伸缩

  • 当主节点发生问题后没推选新的主节点,会将宕机的主节点的分片数据迁移到其他节点上,保证数据的安全,当宕机的主节点恢复后,变为从节点,其他节点将分片信息返回给宕机的主节点
    在这里插入图片描述
    在这里插入图片描述

新增流程过程

  • 新增文档后,进行hash运算,由主节点进行分发,路由到对应的节点分片中,分片进行保存文档的操作,同步给分片副本,将结果返回给主节点在这里插入图片描述
  • 查询
  • 分散阶段,先会找到协同节点(主节点),将请求分散到每一个分片上
  • 聚集阶段,进行数据的操作,将数据返回至协调节点,操作数据,将数据返回给用户
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值