ElasticSearch

前提

了解ElasticSearch之前先来了解一下什么事正向索引和倒排索引

正向索引

ElasticSearch_第1张图片

倒排索引

ElasticSearch_第2张图片

总结:

ElasticSearch_第3张图片

  • 正向索引:根据id找到文档
  • 反向索引:根据文档找到词

Elasticsearch与MySQL概念对比

ElasticSearch_第4张图片

Elasticsearch与MySQL之间关系(相辅相成)

复杂查询用Elasticsearch,简单查询和增删改用MySQL,当然,增删改MySQL数据也需要同步到Elasticsearch中。

ElasticSearch_第5张图片

安装ES

Docker安装

docker run -d \
    --name es \
    -e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \  #内存大小
    -e "discovery.type=single-node" \                        #非集群模式
    -v es-data:/usr/share/elasticsearch/data \           #挂载逻辑卷,绑定es的数据目录
    -v es-plugins:/usr/share/elasticsearch/plugins \  #挂载逻辑卷,绑定es的插件目录
    --privileged \                                                        #授予逻辑卷访问权
    --network=es \                                                     #加入一个名为es的网络中
    -p 9200:9200 \                                                    #端口映射配置
    -p 9300:9300 \
elasticsearch:7.12.1

安装kibana

为什么安装kibana?

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

Docker安装

docker run \
 -d \
 --name kibana \
 -e ELASTICSEARCH_URL=http://es:9200 \ #指定ElasticSearch主机地址
 --network=es \ #加入一个名为es的网络中,与elasticsearch在同一个网络中
 -p 5601:5601 \
 kibana:7.12.1

-e ELASTICSEARCH_URL=http://es:9200":设置elasticsearch的地址,因为kibana已经与elasticsearch在一个网络,因此可以用容器名直接访问elasticsearch

kibana访问报错,连接不上ElasticSearch

1. 进入kibana容器:docker exec -it kibana /bin/bash

2. 修改/config/kibana.yml

3. 将端口号改成你的ElasticSearch端口号即可,docker同一网络中用可通过容器名访问

如:http:es:9200

安装ik分词器

默认分词器对中文分词不友好。

安装分词器版本必须与ES版本保持一致。

elasticsearch ik分词器的安装和使用_宫凯宁的博客-CSDN博客_elasticsearch ik分词器elasticsearch几种常用分词器如下:分词器分词方式StandardAnalyzer单字分词CJKAnalyzer二分法IKAnalyzer词库分词其中常用的是IKAnalyzer,但IK是第三方插件,需要安装。...https://blog.csdn.net/weixin_44723434/article/details/89888489

在线安装

# 进入容器内部
docker exec -it elasticsearch /bin/bash

# 在线下载并安装
./bin/elasticsearch-plugin  install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v8.1.2/elasticsearch-analysis-ik-8.1.2.zip

#退出
exit
#重启容器
docker restart elasticsearch

离线安装

1)查看数据卷目录

安装插件需要知道elasticsearch的plugins目录位置,而我们用了数据卷挂载,因此需要查看elasticsearch的数据卷目录,通过下面命令查看:

docker volume inspect es-plugins

 显示结果:

[
    {
        "CreatedAt": "2022-05-06T10:06:34+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/es-plugins/_data",
        "Name": "es-plugins",
        "Options": null,
        "Scope": "local"
    }
]

说明plugins目录被挂载到了:/var/lib/docker/volumes/es-plugins/_data这个目录中。  

2)解压缩分词器安装包

ik分词器解压缩,重命名为ik

ElasticSearch_第6张图片

3)上传到es容器的插件数据卷中

也就是/var/lib/docker/volumes/es-plugins/_data

ElasticSearch_第7张图片

4)重启容器

# 4、重启容器
docker restart es

# 查看es日志
docker logs -f es

5)去Kibana测试:

IK分词器包含两种模式:

  • ik_smart:粗粒分词,分出的词相对较少,但占用内存空间也较少

  • ik_max_word:最细切分,分出的词相对更细,但占用内存空间也更多

GET /_analyze
{
  "analyzer": "ik_max_word",        //分词解析方式
  "text": "黑马程序员学习java太棒了"

结果:

{
  "tokens": [
    {
      "token": "发文",
      "start_offset": 0,
      "end_offset": 2,
      "type": "CN_WORD",
      "position": 0
    },
    {
      "token": "助手",
      "start_offset": 2,
      "end_offset": 4,
      "type": "CN_WORD",
      "position": 1
    },
    {
      "token": "会",
      "start_offset": 4,
      "end_offset": 5,
      "type": "CN_CHAR",
      "position": 2
    },
    {
      "token": "检测",
      "start_offset": 5,
      "end_offset": 7,
      "type": "CN_WORD",
      "position": 3
    },
    {
      "token": "您",
      "start_offset": 7,
      "end_offset": 8,
      "type": "CN_CHAR",
      "position": 4
    },
    {
      "token": "的",
      "start_offset": 8,
      "end_offset": 9,
      "type": "CN_CHAR",
      "position": 5
    },
    {
      "token": "文章",
      "start_offset": 9,
      "end_offset": 11,
      "type": "CN_WORD",
      "position": 6
    },
    {
      "token": "标题",
      "start_offset": 11,
      "end_offset": 13,
      "type": "CN_WORD",
      "position": 7
    }
  ]
}

ES-IK分词器拓展和停用词典

ElasticSearch_第8张图片

IKAnalyzer.cfg.xml:扩展和通用词典文件所在位置配置

ext.dic:IKAnalyzer.cfg.xml中配置的扩展词典

stopword.dic:IKAnalyzer.cfg.xml中配置的停用词典

为什么要配置扩展词典和停用词典?

扩展词典:可能会有一些全新词IK分词器之前并没有加入到词典中,这时候就需要我们配置一些新出现的词,IK分词器才能在分词的时候把他们当做一个词来看待。如:绝绝子,鲲鲲等

停用词典:敏感词屏蔽

操作索引库

mapping属性

ElasticSearch_第9张图片

 index:是否创建倒排索引,是否参与搜索。

增删改查索引库(表)-

ElasticSearch_第10张图片

创建索引库(表)案例:

PUT /hotel
{
  "mappings": {
    "properties": {
      "id":{    //id通常设置为不分词的字符串字段
        "type": "keyword"
      },
      "name":{
        "type": "text",
        "analyzer": "ik_max_word",
        "copy_to": "all"    //联合索引到all字段
      },
      "address":{
        "type": "keyword",
        "index": false
      },
      "price":{
        "type": "integer"
      },
      "score":{
        "type": "integer"
      },
      "brand":{
        "type": "keyword",
        "copy_to": "all"
      },
      "city":{
        "type": "keyword"
      },
      "star_name":{
        "type": "keyword"
      },
      "business":{
        "type": "keyword",
        "copy_to": "all"
      },
      "location":{
        "type": "geo_point"    //坐标类型:经纬度类型-> 格式为:"经度,纬度" 
      },
      "pic":{
        "type": "keyword",
        "index": false
      },
      "all":{    //联合索引字段
        "type":"text",
        "analyzer": "ik_max_word"
      }
    }
  }
}

增删改查文档(数据)-

ElasticSearch_第11张图片

RestClient操作索引库

1. 分析数据结构

ES-Mapping需要考虑到的问题:

字段名、数据类型、是否参与搜索、是否分词、分词器用什么.....

ElasticSearch_第12张图片

2. 导入RestClient依赖


    
    7.12.1



    org.elasticsearch.client
    elasticsearch-rest-high-level-client

3. 初始化RestHighLevelClient对象(Java高级REST客户端对象),通过该对象连接ES,调用API完成对应数据操作

    //创建RestHighLevelClient对象,连接ES客户端
    RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
        HttpHost.create("http://59.110.233.175:9200")
    ));

    //销毁RestHighLevelClient对象
    client.close();

ElasticSearch_第13张图片

4. 创建索引库

    /**
     * 创建Hotel索引库
     */
    @Test
    public void testCreateHotelIndex() throws IOException {
        //1. 初始化索引库请求对象
        CreateIndexRequest request = new CreateIndexRequest("hotel");
        //2. 请求参数,mappings,可以是一段静态常量字符串,内容是创建索引库的DSL
        request.source(MAPPING_TEMPLATE, XContentType.JSON);
        //3. 发起请求
        client.indices().create(request, RequestOptions.DEFAULT);
    }

    MAPPING_TEMPLATE = "{\n" +
            "  \"mappings\": {\n" +
            "    \"properties\": {\n" +
            "      \"id\":{    //id通常设置为不分词的字符串字段\n" +
            "        \"type\": \"keyword\"\n" +
            "      },\n" +
            "      \"name\":{\n" +
            "        \"type\": \"text\",\n" +
            "        \"analyzer\": \"ik_max_word\",\n" +
            "        \"copy_to\": \"all\"    //联合索引到all字段\n" +
            "      },\n" +
            "      \"address\":{\n" +
            "        \"type\": \"keyword\",\n" +
            "        \"index\": false\n" +
            "      },\n" +
            "      \"price\":{\n" +
            "        \"type\": \"integer\"\n" +
            "      },\n" +
            "      \"score\":{\n" +
            "        \"type\": \"integer\"\n" +
            "      },\n" +
            "      \"brand\":{\n" +
            "        \"type\": \"keyword\",\n" +
            "        \"copy_to\": \"all\"\n" +
            "      },\n" +
            "      \"city\":{\n" +
            "        \"type\": \"keyword\"\n" +
            "      },\n" +
            "      \"star_name\":{\n" +
            "        \"type\": \"keyword\"\n" +
            "      },\n" +
            "      \"business\":{\n" +
            "        \"type\": \"keyword\",\n" +
            "        \"copy_to\": \"all\"\n" +
            "      },\n" +
            "      \"location\":{\n" +
            "        \"type\": \"geo_point\"    //坐标类型:经纬度类型-> 格式为:\"经度,纬度\" \n" +
            "      },\n" +
            "      \"pic\":{\n" +
            "        \"type\": \"keyword\",\n" +
            "        \"index\": false\n" +
            "      },\n" +
            "      \"all\":{    //联合索引字段\n" +
            "        \"type\":\"text\",\n" +
            "        \"analyzer\": \"ik_max_word\"\n" +
            "      }\n" +
            "    }\n" +
            "  }\n" +
            "}";

ElasticSearch_第14张图片

5. 查询和删除索引库

    /**
     * 查询索引库是否存在
     */
    @Test
    public void testExistsHotelIndex() throws IOException {
        GetIndexRequest request = new GetIndexRequest("hotel");
        boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
        System.out.println(exists ? "索引库存在" : "索引库不存在");
    }
    /**
     * 删除索引库
     */
    @Test
    public void testDeleteHotelIndex() throws IOException {
        DeleteIndexRequest request = new DeleteIndexRequest("hotel");
        client.indices().delete(request,RequestOptions.DEFAULT);
    }

ElasticSearch_第15张图片

RestClient操作文档

1. 添加文档

    /**
     * 添加文档(数据)
     */
    @Test
    void testAddDocument() throws IOException {
        //根据id查询
        Hotel hotel = hotelService.getById(61083l);
        //转换为文档类型
        HotelDoc hotelDoc = new HotelDoc(hotel);

        //1. 创建Request对象
        IndexRequest request = new IndexRequest("hotel").id(hotel.getId().toString());
        //2. 准备JSON文档   将对象序列化为JSON格式
        request.source(JSON.toJSONString(hotelDoc),XContentType.JSON);
        //3. 发送请求
        client.index(request,RequestOptions.DEFAULT);
    }

ElasticSearch_第16张图片

批量导入

    /**
     * 批量操作(添加、更新、删除)文档
     */
    @Test
    void bulkAddDocument() throws IOException {
        //批量查询酒店数据
        List hotels = hotelService.list();

        //1. 创建请求
        BulkRequest request = new BulkRequest();
        //2. 请求参数设置
        for (Hotel hotel : hotels) {
            //2.1 解析数据
            HotelDoc hotelDoc = new HotelDoc(hotel);
            //2.2 添加IndexRequest请求到bulk(为Bulk请求做准备)
            request.add(new IndexRequest("hotel")
                    .id(hotelDoc.getId().toString())
                    .source(JSON.toJSONString(hotelDoc),XContentType.JSON));
        }
        //3. 发送请求
        client.bulk(request,RequestOptions.DEFAULT);
    }

ElasticSearch_第17张图片

 

2. 查询文档

    /**
     * 查询文档(数据)
     */
    @Test
    void testGetDocument() throws IOException {
        //1. 创建请求
        GetRequest request = new GetRequest("hotel","61083");
        //2. 发送请求,返回响应结果
        GetResponse response = client.get(request, RequestOptions.DEFAULT);
        //3. 解析响应结果
        String jsonString = response.getSourceAsString();
        HotelDoc hotelDoc = JSON.parseObject(jsonString, HotelDoc.class);
        System.out.println(hotelDoc);
    }

ElasticSearch_第18张图片

 

3. 更新文档

    /**
     * 更新文档(数据)
     */
    @Test
    void testUpdateDocument() throws IOException {
        //1. 创建请求
        UpdateRequest request = new UpdateRequest("hotel", "61083");
        //2. 请求参数
        Map map = new HashMap<>();
        map.put("price","550");
        map.put("starName","四钻");
        request.doc(map);
        //3. 发送请求
        client.update(request,RequestOptions.DEFAULT);
    }

全量更新:再次写入id一样的文档,会覆盖掉原文档,写入id不存在的文档会添加文档(不常用)

局部更新:只更新部分字段

ElasticSearch_第19张图片

4. 删除文档

    /**
     * 删除文档(数据)
     */
    @Test
    void testDeleteDocument() throws IOException {
        //1. 创建请求
        DeleteRequest request = new DeleteRequest("hotel","61083");
        //2. 发送请求
        client.delete(request,RequestOptions.DEFAULT);
    }

你可能感兴趣的:(elasticsearch,搜索引擎)