三方件-1 ElasticSearch概念介绍和案例解析

Posted Ewen Seong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了三方件-1 ElasticSearch概念介绍和案例解析相关的知识,希望对你有一定的参考价值。

背景

最近紧急承接了一个以ES为基础的项目,核心功能是数据检索,然而我发现项目的性能有大问题😡亟待优化。因此ES学习任务的优先级被提到了最高,而容器化和事务专题的整理任务往后顺延。正好赶上中秋节,有机会巩固一下基础🕴顺便对之前学习的内容进行阶段性总结。
本文作为三方件专题的第一篇,介绍ES的基础内容,包括:ES的基本概念、Http接口以及Java相关API等;分布式相关的概念和ES性能调优等放在ES高级篇中介绍。

本文的核心目的是支撑后续开发中的快速查询,也可以帮助读者快速入门ES。

1.概念

1.1 索引

索引类似mysql的schema,是一个分组的概念,不同的索引库相互隔离;也可以理解成是文档数据的集合。ES对外提供的能力都以HTTP接口形式呈现,而这些接口基本都需要指定索引。在ES节点或集群中可以有任意数量的索引,需要保证索引名全局唯一。

1.2 类型

ES废弃了其他不必要的类型(6.X版本后),目前只有_doc文档类型一种。

1.3 文档

文档以JSON格式存在于索引库中(类似于数据库记录),是ES与外界交互的最小颗粒,入库和查询时都以文档为单位。在百度或google上搜索关键字得到的返回结果就是文档列表。

1.4 mapping

1.4.1 mapping介绍

为所属ES库指定字段类型,可以自己定义(显示映射),也可以让ES自动生成(动态映射);后续入库文档对应的字段类型必须与此保持一致,否则会入库失败并抛出异常。
可在新建索引时同时设置mapping,不设置mapping默认为空:

#创建索引库-同时指定mapping映射
PUT http://localhost:9200/sheng

    "mappings":
        "properties":
            "name":
                "type":"text",
                "index":true,
                "analyzer":"ik_max_word"
            ,
            "age":
                "type":"integer",
                "index":true
            ,
            "email":
                "type":"keyword",
                "index":true
            
        
    

查询sheng索引库的映射:

GET http://localhost:9200/sheng/_mapping
#得到结果:

    "sheng": 
        "mappings": 
            "properties": 
                "age": 
                    "type": "integer"
                ,
                "email": 
                    "type": "keyword"
                ,
                "name": 
                    "type": "text",
                    "analyzer": "ik_max_word"
                
            
        
    

其中:
type为字段指定类型,如keyword和text表示字符串类型,在字段类型汇中进行介绍;
analyzer用于指定入库分析器类型,包括ik_max_word和ik_smart等,后续在分析器中介绍;
index表示是否作为索引,false表示不作为索引,即不进行倒排索引,因此无法作为关键字搜索;

需要注意:mapping中的字段类型只能新增不能修改或删除;

1.4.2 mapping常用的字段类型

1.字符串类型:
ES取消了string类型(5.x版本以后),由text和keyword取代:
(1) text支持分词—全文检索,不支持聚合、排序操作;
(2) keyword不进行分词—直接检索,支持聚合、排序操作。

2.整数和浮点类型:
常见有integer, long, short, byte, double, float(与java无区别🥸略); 注意也可以传入类似"1"等字符串型整数;

3.布尔类型:
boolean(与java无区别🥸略)

4.日期类型:
类型为date,支持以下格式:
[1]2015-01-01, 2015/01/01 12:10:30
[2] long类型的毫秒数
[3] integer的秒数
建议同时使用format指定时间格式(指定后-必须完全匹配), 如:

#POST http://localhost:9200/sheng/_mapping

    "properties":
        "testdayf":
            "type":"date",
            "format": "yyyy-MM-dd HH:mm:ss",
            "index":true
        
    

入库时,文档的testdayf字段必须为 2022-12-12 12:12:12形式,即使2022-12-12也会报错;

5.二进制类型

binary类型接受base64编码的字符串和二进制数据,默认不可搜索
使用被指定为binay类型的字段进行搜索时,抛出如下异常:


    "type": "query_shard_exception",
    "reason": "Binary fields do not support searching",
    "index_uuid": "coAY6GXuRfm7V4Dca5fKpQ",
    "index": "sheng"

返回时,随文档一起放回:

GET http://localhost:9200/sheng/_doc/21

    "_index": "sheng",
    "_type": "_doc",
    "_id": "21",
    "_version": 1,
    "_seq_no": 3,
    "_primary_term": 1,
    "found": true,
    "_source": 
        "name": "sy21",
        "age": 21,
        "binatytest": "1MOyoQIABAAAAAAAAAAAAAAABAAEABkzMau+fbwAACABF..."
    

6.复合类型:
数组: 默认任何字段都可以包括多个值,不过数组中所有值必须具有相同的数据类型
在索引库中新增以下映射:


    "properties": 
        "name": 
            "type": "text",
            "index": true
        ,
        "addr": 
            "type": "text",
            "index": true
        
    

新建文档:

POST http://localhost:9200/sheng/_doc/1

    "name":"sy1",
    "addr":["beijing","nanjing","shanghai"]

查询文档:


    "_index": "sheng",//...
    "_source": 
        "name": "sy1",
        "addr": [
            "beijing",
            "nanjing",
            "shanghai"
        ]
    

对象: JSON格式数据
在索引库中新增以下映射:


    "properties": 
        "name": 
            "type": "text"
        ,
        "addr1": 
            "properties": 
                "addr21": 
                    "type": "text"
                ,
                "addr22": 
                    "properties": 
                        "addr31": 
                            "type": "text"
                        ,
                        "addr32": 
                            "type": "text"
                        
                    
                
            
        
    

新建文档:


    "name": "sy1",
    "addr1": 
        "addr21": "21",
        "addr22": 
            "addr31": "31",
            "addr32": "32"
        
    

查询文档:


    "_index": "sheng", //...
    "_source": 
        "name": "sy1",
        "addr1": 
            "addr21": "21",
            "addr22": 
                "addr31": "31",
                "addr32": "32"
            
        
    

嵌套: Map格式数据
在索引库中新增以下映射:


    "properties": 
        "name": 
            "type": "nested"
        
    

新增文档:


    "name":
        "name1":"1",
        "name2":"2"
    

查询文档:


    "_index": "sheng",//...
    "_source": 
        "name": 
            "name1": "1",
            "name2": "2"
        
    

1.6 分词器

分析器由字符过滤器s、 一个分词器、词元过滤器s组成。其中核心是分词器,因此很多资料上对二者没有严格的区分;过滤器主要用于剥离html元素、字符替换,以及去除停词(如:a, is,the)等。本文不深究分析器内部组成原理,因此后文对分析器和分词器概念不再做区分,一律使用分词器表示。
需要注意的是:text字符类型支持分词而keyword不支持,因此分析器的概念是针对text类型的字符串,对其他类型字段分词没有意义;因此后文提及文档入库以及检索时的分词概念均针对text类型, 不再单独强调。

分词器在文档入库以及检索时发挥作用,可手动指定或使用默认分词器:
文档入库时,分词器的优先级顺序排序如下:

1.字段指定的analyzer(文档中指定或者mapping中指定);
2.settings中配置的默认分词器;
3.使用默认的standard分词器;

检索文档时,分词器的优先级顺序排序如下:

1.搜索时指定的search_analyzer;
2.mapping中对应字段的search_analyzer分词器类型;
3.settings中配置的默认分词器;
4.使用默认的standard分词器;

在ES中,可配置ES自带的或第三方提供的或自定义的分词器。如默认的standard分析器为ES自带,中文相关的ik_smart和ik_max_word插件来自第三方(安装教程见附录2😎),以下简单介绍一下这三类分词器的使用:

standard:

基于unicode文本分割算法进行分词:

POST http://localhost:9200/_analyze

    "analyzer":"standard",
    "text":"I had a dream, when I was young."

按照空格和特殊字符进行分割后,还会将所有单词转为小写:


    "tokens": [
        
            "token": "i",
            "start_offset": 0,
            "end_offset": 1,
            "type": "word",
            "position": 0
        ,
        
            "token": "had",
            "start_offset": 2,
            "end_offset": 5,
            "type": "word",
            "position": 1
        ,
        
            "token": "a",
            "start_offset": 6,
            "end_offset": 7,
            "type": "word",
            "position": 2
        ,
        
            "token": "dream",
            "start_offset": 8,
            "end_offset": 13,
            "type": "word",
            "position": 3
        ,
        
            "token": "when",
            "start_offset": 15,
            "end_offset": 19,
            "type": "word",
            "position": 4
        ,
        
            "token": "i",
            "start_offset": 20,
            "end_offset": 21,
            "type": "word",
            "position": 5
        ,
        
            "token": "was",
            "start_offset": 22,
            "end_offset": 25,
            "type": "word",
            "position": 6
        ,
        
            "token": "young",
            "start_offset": 26,
            "end_offset": 31,
            "type": "word",
            "position": 7
        
    ]

ik_smart和ik_max_word

使用ik_smart分词器:

POST http://localhost:9200/_analyze

    "analyzer":"ik_smart",
    "text":"我年轻时有个梦想"

得到以下分词结果:


    "tokens": [
        
            "token": "我",
            "start_offset": 0,
            "end_offset": 1,
            "type": "CN_CHAR",
            "position": 0
        ,
        
            "token": "年轻",
            "start_offset": 1,
            "end_offset": 3,
            "type": "CN_WORD",
            "position": 1
        ,
        
            "token": "时有",
            "start_offset": 3,
            "end_offset": 5,
            "type": "CN_WORD",
            "position": 2
        ,
        
            "token": "个",
            "start_offset": 5,
            "end_offset": 6,
            "type": "CN_CHAR",
            "position": 3
        ,
        
            "token": "梦想",
            "start_offset": 6,
            "end_offset": 8,
            "type": "CN_WORD",
            "position": 4
        
    ]

使用ik_max_word分词器:


    "tokens": [
        
            "token": "我",
            "start_offset": 0,
            "end_offset": 1,
            "type": "CN_CHAR",
            "position": 0
        ,
        
            "token": "年轻时",
            "start_offset": 1,
            "end_offset": 4,
            "type": "CN_WORD",
            "position": 1
        ,
        
            "token": "年轻",
            "start_offset": 1,
            "end_offset": 3,
            "type": "CN_WORD",
            "position": 2
        ,
        
            "token": "时有",
            "start_offset": 3,
            "end_offset": 5,
            "type": "CN_WORD",
            "position": 3
        ,
        
            "token": "个",
            "start_offset": 5,
            "end_offset": 6,
            "type": "CN_CHAR",
            "position": 4
        ,
        
            "token": "梦想",
            "start_offset": 6,
            "end_offset": 8,
            "type": "CN_WORD",
            "position": 5
        
    ]

发现ik_max_word尽可能地进行拆词和组词,而ik_smart基本按照语义进行拆词。

2.ES和kibana安装流程

2.1 ES安装流程

在MAC上基于brew安装ES流程比较简单:

#1.安装ES
brew install elastic/tap/elasticsearch-full

#2.启动ES
brew services start elastic/tap/elasticsearch-full

验证安装是否成功:

注意ES的版本号,安装kibana和ik插件时需要保持版本一致;

2.2 kibana安装流程

kibana可以作为的可视化工具,安装时需要注意保持kibana与es的版本一致性;

下载后进行解压缩安装:
[1] 修改./config/kibana.yml配置文件

server.host: "0.0.0.0"
elasticsearch.hosts: ["http://localhost:9200"]
i18n.locale: "zh-CN"

[2] 使用非root用户执行kibana

# 注意:给用户添加访问和执行kibana的权限
su seong
sh kibana

安装完kibana后,在5601端口侦听:

如上图所示,该ES实例中只有sheng一个索引库,且该索引库只有一个分片。

另外,开发工具页面提供了与ES交互的接口:

3.HTTP接口介绍

ES对外提供Restful风格的Http接口,部分与Restful风格有出入:如创建索引时使用PUT而非POST.

3.1 索引相关

索引接口格式为:http://localhost:9200/$index_name, 支持 [DELETE, PUT, GET, HEAD]方法,即索引支持新增、按名称删除和查询,不支持修改。

3.1.1 创建索引

PUT http://localhost:9200/sheng
#得到

    "acknowledged": true,
    "shards_acknowledged": true,
    "index": "seong"

如果索引已存在,会抛出异常:resource_already_exists_exception.

3.1.2 删除索引

DELETE http://localhost:9200/sheng
#得到

    "acknowledged": true

被删除的索引不存在时,抛出异常:index_not_found_exception.

3.1.3 查询索引

PUT http://localhost:9200/sheng
#得到

    "acknowledged": true,
    "shards_acknowledged": true,
    "index": "seong"

不存在时,抛出异常:index_not_found_exception.

3.2 mapping相关

映射的接口格式为http://localhost:9200/sheng/_mapping, 支持 [POST, PUT, GET]方法,即映射支持新增、修改和查询,不支持删除;
需要注意🥸映射中字段类型一旦创建,不可修改和删除,因此PUT方法只能新增字段类型。


    "properties": 
        "name1": 
            "type": "text",
            "index": true
        ,
        "name2": 
            "type": "long",
            "index": true
        
    

该接口可同时添加多个字段的类型,操作为事务型,一个失败-所有添加操作都会失败;
注意:mapping的字段类型只能添加不能修改和删除;当新增的字段与原字段相同时-忽略,冲突时-抛出异常;

3.3 settings相关

3.3.1 查询指定索引的settings配置

仅支持PUT和GET方法,支持查询和局部修改;

GET http://localhost:9200/seong1/_settings
#得到

    "seong1": 
        "settings": 
            "index": 
                "creation_date": "1662348474856", // 时间戳
                "number_of_shards": "1", // 分片数
                "number_of_replicas": "0", // 副本数
                "uuid": "Plq_afNyQtuCLSixd9-1vA", // 唯一Id
                "version": 
                    "created": "7090399"以上是关于三方件-1 ElasticSearch概念介绍和案例解析的主要内容,如果未能解决你的问题,请参考以下文章

软通动力HarmonyOS三方件开发指南-ActiveOhos_sqlite组件

分布式搜索elasticsearch 基本概念

Elasticsearch介绍,一些概念的笔记

ElasticSearch概念介绍及环境搭建

ElasticSearch 入门介绍

Elasticsearch学习之Elasticsearch的介绍和基本使用