慢时光~

请叫我:Tom-shushu

有兴趣的大佬可以移步右边我的个人博客浏览:Z-BLOG

输了不可怕,大不了从头再来,我们还年轻---周红

Elasticsearch简介、倒排索引、文档基本操作、分词器

lucene、Solr、Elasticsearch

1、倒排序索引

2、Lucene是类库

3、solr基于lucene

4、ES基于lucene

一、Elasticsearch 核心术语

特点:
1、es可以支持空格查询,多个关键字

2、空格支持

3、拆词查询

4、搜索内容可以高亮

5、海量数据查库
ES 可以对照着 数据库 来理解:
  • 索引index    -------->    表
  • 文档 document    -------->    行(记录)
  • 字段 fields    -------->    列
Elasticsearch的存储形式:
stu_index
{
id: 1001,
name: jason,
age: 19
},
{
id: 1002,
name: tom,
age: 18
},
{
id: 1003,
name: rose,
age: 22
}
集群相关
  • 分片(shard):把索引库拆分为多份,分别放在不同的节点上,比如有3个节点,3个节点的所有数据内容加在一起是一个完整的索引库。分别保存到三个节点上,目的为了水平扩展,提高吞吐量。
  • 备份(replica):每个shard的备份。
简称

shard = primary shard(主分片)
replica = replica shard(备份节点)

二、ES集群架构原理

加入有3TB的数据那么ES向上面的架构模型,每个shard会承担1TB的数据,当一个ES的shard出现故障,那么它的replica就会成为它的角色。

shard和replica机制   

A、index包含多个shard   

B、每个shard都是一个最小工作单元,承载部分数据,lucene实例,完整地建立索引和处理请求的能力  

C、增加或减少节点时,shard会自动地在node中负载均衡   

D、primary shard和replica shard,每个document肯定只存在于某一个primary shard以及其对应的replica shard 中,不可能存在于多个primary shard   

E、replica shard是primary shard 的副本,负责容错以及承担读请求负载   

F、primary shard的数量在创建索引的时候就固定了,replica shard的数量可以随时修改   

G、primary shard不能和自己的replica shard放在同一节点上,但是可以和其它primary shard放在同一节点上

三、倒排索引

ES为什么这么快?

        1、索引方式的区别,es主要是利用倒排索引(inverted index),这个翻译可能会让初次接触的人产生误解,误以为是倒着排序?其实不是这样,一般关系型数据库索引是把某个字段建立起一张索引表,传入这个字段的某个值,再去索引中判断是否有这个值,从而找到这个值所在数据(id)的位置。而倒排索引则是把这个值所在的文档id记录下来,当输入这个值的时候,直接查询出这个值所匹配的文档id,再取出id。所以我们在建立es索引的时候,有分词的概念,相当于可以把filed字段内容拆分,然后索引记录下来。例如“我爱中国”,可以拆分成“我”,“爱”,“中国”,“我爱中国”这五个词,同时记录下来这几个关键词的对应文档数据id是1,当我们查询“我”,“中国”时,都能查出这条数据。而如果使用关系型数据库去查包含“中国”这个关键字的数据的时候,则需要like前后通配全表扫描,无法快速找到关键词所在的数据行。

        2、倒排索引是不可更改的,一旦它被建立了,里面的数据就不会再进行更改。这样做就带来了以下几个好处:

  •  不用给索引加锁,因为不允许被更改,只有读操作,所以就不用考虑多线程导致互斥等问题。
  •  索引一旦被加载到了缓存中,大部分访问操作都是对内存的读操作,省去了访问磁盘带来的io开销。
  •  倒排索引具有不可变性,所有基于该索引而产生的缓存也不需要更改,因为没有数据变更。
  •  倒排索引可以压缩数据,减少磁盘io及对内存的消耗。
倒排索引结构:

如图左边为存储结构,右边为倒排索引,将左边的每条文档值内容进行分词并且记录词频和位置,比如我们现在搜索“集群”两字就会直接按照文档ids进行搜索,得到文档1、2、3条记录,搜索“学习”会得到文档1、3两条记录。

四、Elasticsearch安装

1.下载Elasticsearch  Linux版安装包

官网下载太慢,直接使用我下载好的安装包

链接:https://pan.baidu.com/s/1Na0K7hIFJbGECD9XCwdR4A 
提取码:9oz6 
复制这段内容后打开百度网盘手机App,操作更方便哦
2.安装
  • 解压
tar -zxvf elasticsearch-7.10.1-linux-x86_64.tar.gz 
  • 将解压的文件移动到 /usr/local下面
mv elasticsearch-7.10.1  /usr/local
  • 进入目录查看
cd /usr/local/elasticsearch-7.10.1
ll
  • ES 目录介绍

bin:可执行文件在里面,运行es的命令就在这个里面,包含了一些脚本文件等

config:配置文件目录

JDK:java环境

lib:依赖的jar,类库

logs:日志文件

modules:es相关的模块

plugins:可以自己开发的插件

data:这个目录没有,自己新建一下,后面要用 -> mkdir data,这个作为索引目录

  • 修改核心配置文件 elasticearch.yml
  1. 修改集群名称,默认是elasticsearch,虽然目前是单机,但是也会有默认的
  2. 为当前的es节点取个名称,名称随意,如果在集群环境中,都要有相应的名字
  3. 修改data数据保存地址
  4. 修改日志数据保存地址

    5.绑定es网络ip,原理同redis

    6.默认端口号9200,可以自定义修改

    7.集群节点,名字可以先改成之前的那个节点名称

  • 修改JVM参数

默认xms和xmx都是1g,我使用的是虚拟机内存没这么大,修改一下即可

vim jvm.options

  • 添加用户

ES不允许使用root操作es,需要添加用户,操作如下:

useradd esuser
chown -R esuser:esuser /usr/local/elasticsearch-7.4.2
whoami
  • 解决启动保存问题
  1. 修改 limits.conf 文件
vim /etc/security/limits.conf

    在尾部添加如下内容

* soft nofile 65536
* hard nofile 131072
* soft nproc 2048
* hard nproc 4096

    2. 修改 sysctl.conf 文件

vim  /etc/sysctl.conf

    在下面添加如下内容

vm.max_map_count=262145

  • 启动
  1. 切换到刚才创建的用户下
su  esuser

    2. 到ES的bin目录下面

cd /usr/local/elasticsearch-7.10.1/bin

    3.启动

./elasticsearch  ## 前台启动
./elasticsearch -d  ## 后台启动
  • 测试

在浏览器输入 虚拟器IP + ES端口号

​9200:Http协议,用于外部通讯

9300:Tcp协议,ES集群之间是通过9300通讯

http://192.168.2.223:9200/

成功

  • 安装ES可视化工具ES-Header

github地址:https://github.com/mobz/elasticsearch-head

为方便起见我使用Google插件进行安装,备注:需要能谷歌上网

安装完成后如下所示为用ES-Header查看我们刚才安装后的ES节点信息:

 

  • 解决跨域问题

在 elasticearch.yml 中加入如下内容即可:

http.cors.enabled: true
http.cors.allow-origin: "*"

 五、ES文档的基本操作--增删改查

1、增加操作

如果索引没有手动建立mapping,那么插入文档数据时,会根据文档类型自动设置属性类型。这个就是es动态映射,帮我们在index索引库中去建立数据结构的相关配置。
  • 在可视化工具中建一个索引命名为 my_doc

  • 手动添加文档数据
在postman里面发送post请求到http://192.168.2.223:9200/my_doc/_doc/1
注意:my_doc为索引名、_doc为文档类型、1为为文档起的id唯一编号(如果不指定系统会为每条数据自动分配一个)
添加数据:
http://192.168.2.223:9200/my_doc/_doc/1
{
"id": 1001,
"name": "zhouhong-1",
"desc": "zhouhong is my good fridend!",
"create_date": "2021-02-19"
}

http://192.168.2.223:9200/my_doc/_doc/2
{
"id": 1002,
"name": "zhouhong-2",
"desc": "zhouhong 是一个好人",
"create_date": "2021-02-18"
}

http://192.168.2.223:9200/my_doc/_doc/3
{
"id": 1003,
"name": "zhouhong-3",
"desc": "zhouhong 真的是一个好人",
"create_date": "2021-02-18"
}

http://192.168.2.223:9200/my_doc/_doc/4
{
"id": 1004,
"name": "zhouhong-4",
"desc": "zhouhong is her friend",
"create_date": "2021-02-18"
}

http://192.168.2.223:9200/my_doc/_doc/5
{
"id": 1005,
"name": "zhouhong-5",
"desc": "zhouhong is 好人",
"create_date": "2021-02-18"
}

http://192.168.2.223:9200/my_doc/_doc/6
{
"id": 1006,
"name": "zhouhong-6",
"desc": "zhouhong is realy good man",
"create_date": "2021-02-18"
}
  • 检查是否添加成功

2、删除

直接调用 http://192.168.2.223:9200/my_doc/_doc/6 发送DELETE请求既可
注意:这里的删除操作不是真正的删除,只是逻辑上的删除(添加标识符)ES属于被动删除,只有在磁盘满了的时候会被动删除。

3、修改请求

直接调用:http://192.168.2.223:9200/my_doc/_doc/6/_update 发送POST请求
入参:
{
    "doc": {
        "name" "周红"
    }
}

4、查询

  • 根据文档id查询
直接发送GET请求http://192.168.2.223:9200/my_doc/_doc/6
相当于:select * from my_doc where _id = 6
结果:
{
    "_index": "my_doc",
    "_type": "_doc",
    "_id": "6",
    "_version": 2,
    "_seq_no": 17,
    "_primary_term": 1,
    "found": true,
    "_source": {
        "id": 1006,
        "name": "zhouhong-6",
        "desc": "zhouhong is realy good man",
        "create_date": "2021-02-18"
    }
}
_index:文档数据所属那个索引,理解为数据库的某张表即可。
_type:文档数据属于哪个类型,新版本使用_doc。
_id:文档数据的唯一标识,类似数据库中某张表的主键。可以自动生成或者动指定。
_score:查询相关度,是否契合用户匹配,分数越高用户的搜索体验越高。
_version:版本号。
_source:文档数据,json格式。
  • 查询所有
相当于:select * from my_doc
调用 http://192.168.2.223:9200/my_doc/_doc/_search 发送GET请求
  • 查询部分数据
相当于: select id, name from my_doc where _id = 2
GET请求http://192.168.2.223:9200/my_doc/_doc/1?source=id,name
  • 判断当前索引是否存在文档,以下方式比较规范
发送HEAD请求 http://192.168.31.183:9200/my_doc/_doc/2 根据相应状态码HttpStatusCode:200,则存在,404则不存在
比使用GET查询请求判断文档是否存在效率更高

 

、ES分词器

ES默认只支持英文分词,如果是中文它会拆分为一个一个字

1、默认分词器

a.分词器(会忽略大小写):
  • 标准分词器standard(把单词进行分割)
  • 简单分词器simple(会去除字符串中非字母的元素)
  • 空格分词器whitespace(根据空格进行分割)
  • stop(会去除英文语句中的无意义的单词:the 、is、a等等)
  • keyword(会将整个文本当作一个词,不会被拆分)
b.标准分词器演示:
入参:
{
    "analyzer": "standard",
    "text": "zhouhong is a good man!"
}
结果:
{
    "tokens": [
        {
            "token": "zhouhong",
            "start_offset": 0,
            "end_offset": 8,
            "type": "<ALPHANUM>",
            "position": 0
        },
        {
            "token": "is",
            "start_offset": 9,
            "end_offset": 11,
            "type": "<ALPHANUM>",
            "position": 1
        },
        {
            "token": "a",
            "start_offset": 12,
            "end_offset": 13,
            "type": "<ALPHANUM>",
            "position": 2
        },
        {
            "token": "good",
            "start_offset": 14,
            "end_offset": 18,
            "type": "<ALPHANUM>",
            "position": 3
        },
        {
            "token": "man",
            "start_offset": 19,
            "end_offset": 22,
            "type": "<ALPHANUM>",
            "position": 4
        }
    ]
}

2、IK中文分词器

1.安装
下载与ES对应的IK压缩包上传服务器
  • 将压缩包解压到ES下的 plugins 下
unzip elasticsearch-analysis-ik-7.10.1.zip  -d /usr/local/elasticsearch-7.10.1/plugins/ik
2.测试
  • 使用 ik_max_word(最细粒的拆分) 测试
入参:
{
    "analyzer": "ik_max_word",
    "text": "明天早上吃什么呢"
}
出参:
{
    "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": 7,
            "type": "CN_WORD",
            "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
        }
    ]
}
可见分的很详细,几乎能组成词的都拆分了。
  • 使用 ik_smart 分词器测试
入参:
{
    "analyzer": "ik_smart",
    "text": "明天早上吃什么呢"
}
出参:

 

{
    "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": 7,
            "type": "CN_WORD",
            "position": 2
        },
        {
            "token": "",
            "start_offset": 7,
            "end_offset": 8,
            "type": "CN_CHAR",
            "position": 3
        }
    ]
}

3、自定义中文分词器

IK默认分词器虽然很好用,但是会存在一个问题,像我们的网络用语,姓名等等它会分割为一个一个的字不符合我们的需求比如下面这个情况:
{
    "analyzer": "ik_max_word",
    "text": "周红"
}

{
    "tokens": [
        {
            "token": "",
            "start_offset": 0,
            "end_offset": 1,
            "type": "CN_CHAR",
            "position": 0
        },
        {
            "token": "",
            "start_offset": 1,
            "end_offset": 2,
            "type": "CN_CHAR",
            "position": 1
        }
    ]
}
我们希望它是一个完整的词,而不用被拆分开来。
自定义分词器
  • 在IK分词器安装目录下面的配置文件,增加一个custom.dic的字典文件
vim /usr/local/elasticsearch-7.10.1/plugins/ik/config/IKAnalyzer.cfg.xml

 

  • 在同级目录下新建一个custom.dic文件里面写上我们不需要拆分的词

  • 测试
入参:
{
    "analyzer": "ik_max_word",
    "text": "周红"
}
出参:
{
    "tokens": [
        {
            "token": "周红",
            "start_offset": 0,
            "end_offset": 2,
            "type": "CN_WORD",
            "position": 0
        }
    ]
}

 后面如果想扩展,只需在自定义的custom.dic里面添加词汇即可

 

 

输了不可怕,大不了从头再来,我们还年轻---周红

posted on 2021-02-22 01:47  Tom-shushu  阅读(349)  评论(0编辑  收藏  举报

导航