ElasticSearch-1

原文链接:https://gaoyubo.cn/blogs/52ef5bf7.html

一、Elasticsearch 架构设计

Elasticsearch 架构层:

Elasticsearch 五层架构设计图:

说明:

  • Elasticsearch是基于Lucene架构实现的,所以其核心层为Lucene
  • Elasticsearch 目前支持HTTPThriftMemcache三种协议,默认是HTTP
  • JMX指在Elasticsearch中对 Java 的管理架构,用来管理Elasticsearch应用

二、Docker部署

2.1加载es镜像

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

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

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

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

2.2运行镜像

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:端口映射配置

此时访问9200端口,可以访问到已经部署成功

2.3部署kibana

kibana可以提供一个elasticsearch的可视化界面

docker run -d \
--name kibana \
-e ELASTICSEARCH_HOSTS=http://es:9200 \
--network=es-net \
-p 5601:5601  \
kibana:7.12.1
  • --network es-net :加入一个名为es-net的网络中,与elasticsearch在同一个网络中
  • -e ELASTICSEARCH_HOSTS=http://es:9200":设置elasticsearch的地址,因为kibana已经与elasticsearch在一个网络,因此可以用容器名直接访问elasticsearch
  • -p 5601:5601:端口映射配置

部署成功

2.4离线安装ik插件

查看数据卷目录

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

docker volume inspect es-plugins

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

上传插件

# 重启容器
docker restart es
# 查看es日志
docker logs -f es

扩展词词典

词汇需要不断的更新,IK分词器提供了扩展词汇的功能。

1)打开IK分词器config目录:

2)在IKAnalyzer.cfg.xml配置文件内容添加:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
        <comment>IK Analyzer 扩展配置</comment>
        <!--用户可以在这里配置自己的扩展字典 *** 添加扩展词典-->
        <entry key="ext_dict">ext.dic</entry>
</properties>

3)新建一个 ext.dic,可以参考config目录下复制一个配置文件进行修改

奥力给

4)重启elasticsearch

docker restart es

日志中已经成功加载ext.dic配置文件

注意当前文件的编码必须是 UTF-8 格式,严禁使用Windows记事本编辑

三、索引库操作

3.1创建索引库

索引库就类似数据库表,mapping映射就类似表的结构。

基本语法:

  • 请求方式:PUT
  • 请求路径:/索引库名,可以自定义
  • 请求参数:mapping映射
PUT /index1
{
  "mappings": {
    "properties": {
      "info": {
        "type": "text",
        "analyzer": "ik_smart"
      },
      "email": {
        "type": "keyword",
        "index": false
      },
      "name": {
        "type": "object",
        "properties": {
          "firstName": {
            "type": "keyword"
          },
          "lastName": {
            "type": "keyword"
          }
        }
      }
    }
  }
}

3.2查询索引库

基本语法

  • 请求方式:GET

  • 请求路径:/索引库名

  • 请求参数:无

3.3修改索引库

倒排索引结构虽然不复杂,但是一旦数据结构改变(比如改变了分词器),就需要重新创建倒排索引。因此索引库一旦创建,无法修改mapping

虽然无法修改mapping中已有的字段,但是却允许添加新的字段到mapping中,因为不会对倒排索引产生影响。

语法说明

PUT /索引库名/_mapping
{
  "properties": {
    "新字段名":{
      "type": "integer"
    }
  }
}

四、文档操作

4.1添加文档

POST /索引库名/_doc/文档id
{
    "字段1": "值1",
    "字段2": "值2",
    "字段3": {
        "子属性1": "值3",
        "子属性2": "值4"
    },
    // ...
}

4.2查询文档

语法:

GET /{索引库名称}/_doc/{id}

4.3.删除文档

删除使用DELETE请求,同样,需要根据id进行删除:

语法:

DELETE /{索引库名}/_doc/id值

4.4修改文档

修改有两种方式:

  • 全量修改:直接覆盖原来的文档
  • 增量修改:修改文档中的部分字段

全量修改

全量修改是覆盖原来的文档,其本质是:

  • 根据指定的id删除文档
  • 新增一个相同id的文档

类似于Java中的HashMap的put操作

PUT /{索引库名}/_doc/文档id
{
    "字段1": "值1",
    "字段2": "值2",
    // ... 略
}

增量修改

增量修改是只修改指定id匹配的文档中的部分字段。

语法:

POST /{索引库名}/_update/文档id
{
    "doc": {
         "字段名": "新的值",
    }
}

五、RestAPI操作索引库

官方地址

其中的Java Rest Client又包括两种:

  • Java Low Level Rest Client
  • Java High Level Rest Client

image-20231218160053382

译文:

Java底层REST客户端:Elasticsearch的官方底层客户端。它允许通过http与Elasticsearch集群通信。将请求编组和响应反编组留给用户。它与所有Elasticsearch版本兼容。

Java高级REST客户端:Elasticsearch的官方高级客户端。基于底层客户端,它公开了特定于API的方法,并负责请求编组和响应反编组。

我们学习的是Java HighLevel Rest Client客户端API

mapping映射分析

创建索引库,最关键的是mapping映射,而mapping映射要考虑的信息包括:

  • 字段名
  • 字段数据类型
  • 是否参与搜索
  • 是否需要分词
  • 如果分词,分词器是什么?

其中:

  • 字段名、字段数据类型,可以参考数据表结构的名称和类型
  • 是否参与搜索要分析业务来判断,例如图片地址,就无需参与搜索
  • 是否分词呢要看内容,内容如果是一个整体就无需分词,反之则要分词
  • 分词器,我们可以统一使用ik_max_word
  • id主键特殊,不实用long,而是使用keyword

MySQL数据结构如下:

CREATE TABLE `tb_hotel` (
  `id` bigint(20) NOT NULL COMMENT '酒店id',
  `name` varchar(255) NOT NULL COMMENT '酒店名称;例:7天酒店',
  `address` varchar(255) NOT NULL COMMENT '酒店地址;例:航头路',
  `price` int(10) NOT NULL COMMENT '酒店价格;例:329',
  `score` int(2) NOT NULL COMMENT '酒店评分;例:45,就是4.5分',
  `brand` varchar(32) NOT NULL COMMENT '酒店品牌;例:如家',
  `city` varchar(32) NOT NULL COMMENT '所在城市;例:上海',
  `star_name` varchar(16) DEFAULT NULL COMMENT '酒店星级,从低到高分别是:1星到5星,1钻到5钻',
  `business` varchar(255) DEFAULT NULL COMMENT '商圈;例:虹桥',
  `latitude` varchar(32) NOT NULL COMMENT '纬度;例:31.2497',
  `longitude` varchar(32) NOT NULL COMMENT '经度;例:120.3925',
  `pic` varchar(255) DEFAULT NULL COMMENT '酒店图片;例:/img/1.jpg',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

根据MySQL表结构构造了如下的mapping映射

PUT /hotel
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "name":{
        "type": "text",
        "analyzer": "ik_max_word",
        "copy_to": "all"
      },
      "address":{
        "type": "keyword",
        "index": false
      },
      "price":{
        "type": "integer"
      },
      "score":{
        "type": "integer"
      },
      "brand":{
        "type": "keyword",
        "copy_to": "all"
      },
      "city":{
        "type": "keyword",
        "copy_to": "all"
      },
      "starName":{
        "type": "keyword"
      },
      "business":{
        "type": "keyword"
      },
      "location":{
        "type": "geo_point"
      },
      "pic":{
        "type": "keyword",
        "index": false
      },
      "all":{
        "type": "text",
        "analyzer": "ik_max_word"
      }
    }
  }
}

此时会发现多出一个all字段:因为如果很多字段都需要倒排索引,那么性能就会下降,ES可以使用cpoy_to属性将当前字段拷贝到指定字段,在指定字段里,统一构造倒排索引。

location:地理坐标,里面包含精度、纬度

初始化RestClient

  1. 引入es的RestHighLevelClient依赖:
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>
<properties>
    <java.version>1.8</java.version>
    <elasticsearch.version>7.12.1</elasticsearch.version>
</properties>

因为SpringBoot进行了自动依赖管理,默认的ES版本是7.6.2,所以需要额外指定固定版本。

  1. 初始化RestHighLevelClient:

初始化的代码如下:

RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
        HttpHost.create("http://xxx:9200") 	
));

创建索引库

 @Test
    void hotelIndexCreate() throws IOException {
        //获取create请求
        CreateIndexRequest createIndexRequest = new CreateIndexRequest("hotel");
        //添加请求参数
        createIndexRequest.source(ESTemplate.CreateHotelTemplate(), XContentType.JSON);
        //发送请求
        client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
    }

添加请求参数时的json语句,就是dev Tools中编写的json语句

删除索引库

@Test
void testDeleteHotelIndex() throws IOException {
    // 1.创建Request对象
    DeleteIndexRequest request = new DeleteIndexRequest("hotel");
    // 2.发送请求
    client.indices().delete(request, RequestOptions.DEFAULT);
}

判断索引库是否存在

@Test
void testExistsHotelIndex() throws IOException {
    // 1.创建Request对象
    GetIndexRequest request = new GetIndexRequest("hotel");
    // 2.发送请求
    boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
    // 3.输出
    System.err.println(exists ? "索引库已经存在!" : "索引库不存在!");
}

索引库操作的基本步骤:

  • 初始化RestHighLevelClient
  • 创建XxxIndexRequest。XXX是Create、Get、Delete
  • 准备DSL( Create时需要,其它是无参)
  • 发送请求。调用RestHighLevelClient#indices().xxx()方法,xxx是create、exists、delete

六、RestAPI操作文档

添加文档

  @Test
    void hotelDocCreate() throws IOException {
        //获取mysql表hotel记录
        Hotel hotel = hotelService.getById(36934L);
        //转化为doc
        HotelDoc hotelDoc = new HotelDoc(hotel);
        
        //获取create请求
        IndexRequest request = new IndexRequest("hotel" ).id(hotelDoc.getId().toString());
        //添加请求参数
        request.source(JSON.toJSONString(hotelDoc),XContentType.JSON);
        //发送请求(文档操作,不需要indices)
        client.index(request,RequestOptions.DEFAULT);
    }

查询文档

@Test
    void testGetDocumentById() throws IOException {
        // 1.准备Request
        GetRequest request = new GetRequest("hotel", "36934");
        // 2.发送请求,得到响应
        GetResponse response = client.get(request, RequestOptions.DEFAULT);
        // 3.解析响应结果
        String json = response.getSourceAsString();

        HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
        System.out.println(hotelDoc);
    }

修改文档

  • 全量修改:本质是先根据id删除,再新增
  • 增量修改:修改文档中的指定字段值

在RestClient的API中,全量修改与新增的API完全一致,判断依据是ID:

  • 如果新增时,ID已经存在,则修改
  • 如果新增时,ID不存在,则新增
 @Test
    void testUpdateDocument() throws IOException {
        // 1.准备Request
        UpdateRequest request = new UpdateRequest("hotel", "36934");
        // 2.准备请求参数
        request.doc(
                "price", "100000000",
                "starName", "四钻"
        );
        // 3.发送请求
        client.update(request, RequestOptions.DEFAULT);
    }

删除文档

@Test
void testDeleteDocument() throws IOException {
    // 1.准备Request
    DeleteRequest request = new DeleteRequest("hotel", "61083");
    // 2.发送请求
    client.delete(request, RequestOptions.DEFAULT);
}

批量添加文档

步骤如下:

  • 利用mybatis-plus查询酒店数据
  • 将查询到的酒店数据(Hotel)转换为文档类型数据(HotelDoc)
  • 利用JavaRestClient中的BulkRequest批处理,实现批量新增文档

@Test
void testBulkRequest() throws IOException {
// 批量查询酒店数据
List hotels = hotelService.list();

// 1.创建Request
BulkRequest request = new BulkRequest();
// 2.准备参数,添加多个新增的Request
for (Hotel hotel : hotels) {
    // 2.1.转换为文档类型HotelDoc
    HotelDoc hotelDoc = new HotelDoc(hotel);
    // 2.2.创建新增文档的Request对象
    request.add(new IndexRequest("hotel")
                .id(hotelDoc.getId().toString())
                .source(JSON.toJSONString(hotelDoc), XContentType.JSON));
}
// 3.发送请求
client.bulk(request, RequestOptions.DEFAULT);

}

posted @ 2023-12-25 03:27  橡皮筋儿  阅读(7)  评论(0编辑  收藏  举报