ElasticSearch

ElasticSearch

小龙 551 2020-03-03

ElasticSearch简介

ElasticSearch是一个开源的分布式/RESTful风格的搜索引擎和数据分析引擎,它底层是开源库“Lucene”。ElasticSearch使用Java语言开发,现由Apache基金会维护,是目前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定、可靠、快速,安装方便。
我们建立一个网站,并要添加搜索功能,但是想要完成搜索工作是非常困难的。我们希望搜索解决方案要运行速度快,我们希望能有一个零配置和一个完全免费的搜索模式,我们希望能够简单使用JSON通HTTP来索引数据,我们希望我们的搜索服务器始终可用,我们希望能够从一台服务器扩展到上百台,数百条,我们要实时搜索,我们要简单的多租户,我们希望建立一个云的解决方案,因此我门使用ElasticSearch来解决这些问题以及可能出现的更多的其他问题

官方网址:https://www.elastic.co/cn/products/elasticsearch
Github:https://github.com/elastic/elasticsearch

ElasticSearch是基于Lucene的,Lucene可以说是当下最先进、高性能、全功能的搜索引擎库——无论是开源还是私有,但它仅仅只是一个库。为了充分发挥其功能,你需要使用Java并将Lucene直接集成在到应用程序。更糟糕的是,你可能需要获得信息检索学位才能了解其工作原理,因为Lucene非常的复杂。
为了解决Lucene使用时的繁复性,于是ElasticSearch便应运而生,它使用Java语言编写,内部采用Lucene做索引与搜索,但是它的目标是使全文检索变得更加简单,简单的来说就是对Lucene做了一层封装,它提供了一套简单一致的RESTful API来帮助我们实现存储和检索
当然ElasticSearch不仅仅是Lucene,并且也不仅仅是一个全文搜索引擎。用下面的来形容更加的准确

  • 一个分布式的实时文档存储,每个字段可以被索引与搜索
  • 一个分布式实时分析搜索引擎
  • 能胜任上百个服务节点的扩展,并支持PB级别的结构化或者非结构化数据
    由于ElasticSearch的功能简单强大和简单使用,像维基百科、GitHub等都采用它来做搜索。现在ElasticSearch依据成为全文搜索领域最为主流的程序之一

安装ElasticSearch

1、将下载的ES文件上传到服务器之中,并解压

tar xzvf /srv/ftp/elasticsearch-7.6.0-linux-x86_64.tar.gz -C /usr/local/

2、将解压后的文件重命名,方便后续操作

mv /usr/local/elasticsearch-7.6.0/ /usr/local/elasticsearch

3、新建ElasticSearch数据存储目录

mkdir -p /usr/data/elasticSearch/{data,logs}

4、修改config/elasticsearch.yml文件

vim /usr/local/elasticsearch/config/elasticsearch.yml

取消下列项注释并修改:
cluster.name: my-application #集群名称
node.name: node-1 #节点名称
#数据和日志的存储目录
path.data: /usr/data/elasticSearch/data
path.logs: /usr/data/elasticSearch/logs
#设置绑定的ip,设置为0.0.0.0以后就可以让任何计算机节点访问到了
network.host: 0.0.0.0
http.port: 9200 #端口
#设置在集群中的所有节点名称,这个节点名称就是之前所修改的,当然你也可以采用默认的也行,目前是单机,放入一个节点即可
cluster.initial_master_nodes: ["node-1"]

5、启动ElasticSearch,在启动的时候需要注意,ElasticSearch为了安全,不允许“root”用户进行启动,所有我们需要创建一个用户进行启动

# 创建elasticsearch用户
adduser elasticsearch
# 设置密码,要输入两次:“passwd 用户名”
passwd elasticsearch
# 将对应的文件夹权限赋给该用户
chown -R elasticsearch /usr/local/elasticsearch/ -R
chown -R elasticsearch /usr/data/elasticSearch/ -R

6、vim 编辑 /etc/security/limits.conf,在末尾加上:“*”替换为新的用户名

* soft nofile 65536
* hard nofile 65536
* soft nproc 4096
* hard nproc 4096

7、vim 编辑 vim /etc/security/limits.d/20-nproc.conf,将* 改为用户名

# Default limit for number of user's processes to prevent
# accidental fork bombs.
# See rhbz #432903 for reasoning.

elasticsearch          soft    nproc     4096
root       soft    nproc     unlimited

8、vim 编辑 /etc/sysctl.conf,在末尾加上:

vm.max_map_count = 262144

9、在“:/etc/security/”目录执行:sysctl -p

返回:
vm.max_map_count = 262144

10、切换新建的用户

su elasticsearch

启动提示:Java版本需要升级到JDK11
解决:下载Jdk11:wget https://download.java.net/java/GA/jdk11/13/GPL/openjdk-11.0.1_linux-x64_bin.tar.gz
tar -xzvf jdk-11.0.4_linux-x64_bin.tar.gz -C /use/local/
mv /use/local/jdk-11 /use/local/jdk11
修改:vi bin/elasticsearch 添加配置项
#配置自己的jdk11
export JAVA_HOME=/opt/jdk-11.0.1
export PATH=$JAVA_HOME/bin:$PATH

#添加jdk判断
if [ -x "$JAVA_HOME/bin/java" ]; then
JAVA="/opt/jdk-11.0.1/bin/java"
else
JAVA=which java
fi

修改config/jvm.options
注释掉其它,添加下面的配置
-XX:+UseG1GC
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly

错误:ElasticsearchException[Failure running machine learning native code. This could be due to running on an unsupported OS or distribution, missing OS libraries, or a problem with the temp directory. To bypass this problem by running Elasticsearch without machine learning functionality set [xpack.ml.enabled: false].]

解决:vim config/elasticsearch.yml添加一条配置:
xpack.ml.enabled: false

11、启动

/usr/local/elasticsearch/bin/elasticsearch

12、在浏览器中输入:http://ip:9200,返回下面的内容,启动成功

{
  "name" : "node-1",
  "cluster_name" : "my-application",
  "cluster_uuid" : "v4W4Jen8RWKPhTfUMIqpIA",
  "version" : {
    "number" : "7.6.0",
    "build_flavor" : "default",
    "build_type" : "tar",
    "build_hash" : "7f634e9f44834fbc12724506cc1da681b0c3b1e3",
    "build_date" : "2020-02-06T00:09:00.449973Z",
    "build_snapshot" : false,
    "lucene_version" : "8.4.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

13、上面的是在前台启动,如果需要后台启动加上“-d”即可

/usr/local/elasticsearch/bin/elasticsearch -d
# 查看启动结果:ps -ef|grep elasticsearch
root       4194   4125  0 22:03 pts/0    00:00:00 su elasticsearch
elastic+   4618      1 98 22:10 pts/0    00:00:20 /usr/local/jdk/bin/java -Des.networkaddress.cache.ttl=60 -Des.networkaddress.cache.negative.ttl=10 -XX:+AlwaysPreTouch -Xss1m -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Djna.nosys=true -XX:-OmitStackTraceInFastThrow -Dio.netty.noUnsafe=true -Dio.netty.noKeySetOptimization=true -Dio.netty.recycler.maxCapacityPerThread=0 -Dio.netty.allocator.numDirectArenas=0 -Dlog4j.shutdownHookEnabled=false -Dlog4j2.disable.jmx=true -Djava.locale.providers=COMPAT -Xms1g -Xmx1g -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -Djava.io.tmpdir=/tmp/elasticsearch-10955069239077689375 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=data -XX:ErrorFile=logs/hs_err_pid%p.log -Xlog:gc*,gc+age=trace,safepoint:file=logs/gc.log:utctime,pid,tags:filecount=32,filesize=64m -XX:MaxDirectMemorySize=536870912 -Des.path.home=/usr/local/elasticsearch -Des.path.conf=/usr/local/elasticsearch/config -Des.distribution.flavor=default -Des.distribution.type=tar -Des.bundled_jdk=true -cp /usr/local/elasticsearch/lib/* org.elasticsearch.bootstrap.Elasticsearch -d
elastic+   4633   4618  0 22:10 pts/0    00:00:00 /usr/local/elasticsearch/modules/x-pack-ml/platform/linux-x86_64/bin/controller
elastic+   4683   4195  0 22:10 pts/0    00:00:00 grep --color=auto elasticsearch

ElasticSearch基本配置:当服务成功启动之后,就安装完成了,随后就可以对ElasticSearch进配置
ElasticSearch可配置信息
|属性名|说明|
|-------|-------|
|cluster.name|配置ElasticSearch的集群名称,默认是elasticsearch,有需要可以修改一个有意义的名称|
|node.name|节点名称,es会默认随机指定一个名称,建议指定一个有意义的名称,方便管理|
|path.conf|设置索引数据的存储路径,默认是es根目录下的data文件夹,可以设置多个存储路径,使用逗号“,”隔开|
|path.logs|设置日志文件的存储路径,默认是es根目录下的logs文件夹|
|path.plugins|设置插件的存放路径,默认是es根目录下的plugins文件夹|
|bootstart.memory_lock|设置为true可以锁定ES使用的内存,避免内存进行swap|
|network.host|设置bind_host和publish_host,设置为0.0.0.0允许外网访问|
|http:port|设置对外服务的http端口,默认为9200|
|transport.port|集群节点直接通信接口|
|discovery.zen.minimum_master_nodes|主节点数量的最少值,此值的公式为:(master_eligible_nodes/2)+1,比如:有三个符合要求的主节点,那么这里要设置为2|

概念

在逻辑层面

  • Index(索引):这里的Index是名称,一个Index就像是传统关系型数据库的DataBase(库),它是ElasticSearch用来存储数据的逻辑区域
  • Type(类型):文档属于一种Type,Type就像是关系型数据库中的一个Table(表)
  • Document(文档):ElasticSreach使用JSON文档来表示一个对象,就像是关系型数据库一个表中的一个(ROW)行
  • Field(字段):每个文档包含多个字段,就像是关系型数据库一张表中的一个(Column)列

在物理层面

  • Node(节点):node是一个运行着的ElasticSearch实例,一个node就是一个单独的server
  • cluster(集群):cluster是有多个由node组成
  • Shard(分片):数据分片,一个Index可能会存在于多个Shard中

配置 ik分词器

下载ik分词器:https://github.com/medcl/elasticsearch-analysis-ik
下载的版本要与ElasticSearch的版本一致,否则无法启动
新建ik文件夹:

mkdir -p /usr/local/elasticsearch/plugins/ik

将下载好的ik分词器解压到新建的ik目录中,重启ElasticSearch即可
使用Postman测试ik分词器是否可用,结果如下图所示表示配置成功
kibana2.png

基本使用,使用PostMan测试工具

创建、修改

创建一个关于电影的索引,使用POST请求

192.168.5.168:9200/movie/adventure/1

对该链接的解释:

es.png

使用Postman测试:

es1.png

可以看到,我们已经成功创建了一个 _index 为 movie,_type 为 adventure,_id 为 1 的文档。当前的result为create,上图由于我是第二次保存所以已经边长update了。

查询该索引,使用GET请求

192.168.5.168:9200/movie/adventure/1

es2.png

可以发现我们保存的数据已经在"_source"里面了

如果我们数据没有设置id,ElasticSearch也可以自动生成

POST /movie/adventure/

更新整个文档,使用PUT请求

当我们调用PUT请求指明文档的_index、_type、_id时,如果_id已经存在了,则新的文段会替换掉旧的文档 ,并且此时文档的_version会增加1,result字段会为update
es3.png
es4.png

可以看到,actors 这个字段已经不存在了,文档的 _version 变成了 2。

检索

检索某个文档

检索整个索引比较简单,只要使用GET请求,并指出index(索引名)、type(类型)、id即可

192.168.5.168:9200/movie/adventure/1

响应内容会包含文档的元信息,文档的原数据存在_source字段中,也可以直接检索出_source字段下的数据

192.168.5.168:9200/movie/adventure/1/_source

检索所有文档

192.168.5.168:9200/movie/adventure/_search

es5.png

可以看到,hits这个Object包含了hits数组,total等字段,其中hits数组包含了所有的文当,total表明了文档的数量,默认情况下最多返回10个,也可以设置from=xx&size=xx参数来获取某一范围文档的数量。

query string搜索

query string搜索以:q=field:value的形式进行查询,比如查询name字段中包含有ByXiaoLong的信息,这是完整搜索,必须搜索一个完整的value

192.168.5.168:9200/movie/adventure/_search?q=name:ByXiaoLong

也可以使用下面的方式进行

DSL 搜索

上面的 query string 搜索比较轻量级,只适用于简单的场合。Elasticsearch 提供了更为强大的 DSL(Domain Specific Language)查询语言,适用于复杂的搜索场景,比如全文搜索。我们可以将上面的 query string 搜索转换为 DSL 搜索,如下:

es6.png

删除文档,使用DELETE请求

192.168.5.168:9200/movie/adventure/1

es7.png

  • ElasticSearch通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单
  • 在创建文档的时候,我们可以使用POST方法指定将这个文档添加到某个_index_type下,来让ElasticSearch自动生成唯一的_id;使用PUT方法指定将文档的_index_type_id

Kibana安装

kibana是ElasticSearch优秀的图形化管理工具,包括控制台和图表显示等简易操作
1、解压kbana:

tar xzvf /srv/ftp/kibana-7.6.0-linux-x86_64.tar.gz -C /usr/local/

2、重命名

mv /usr/local/kibana-7.6.0-linux-x86_64/ /usr/local/kibana

3、修改配置文件

mkdir -p /usr/data/kibana/run
vim /usr/local/kibana/config/kibana.yml
取消注释:server.port: 5601
取消注释并修改:server.host: "0.0.0.0"
取消注释并修改:elasticsearch.hosts: ["http://ElasticSearch主机Ip:9200"]
取消注释并修改:pid.file: /usr/data/kibana/run/kibana.pid

4、给elasticsearch用户赋予权限

chown -R elasticsearch /usr/data/kibana/ -R
chown -R elasticsearch /usr/local/kibana/ -R

5、切换用户

su elasticsearch 

6、启动kibana

/usr/local/kibana/bin/kibana &

7、查看进程

ps -ef | grep node
elastic+   5054   5003 41 00:55 pts/1    00:00:33 /usr/local/kibana/bin/../node/bin/node /usr/local/kibana/bin/../src/cli
elastic+   5077   5003  0 00:56 pts/1    00:00:00 grep --color=auto node

8、浏览器输入:

http://ip:5601/

出现下面的界面,启动成功
kibana1.png
在界面有几个重要操作选项
|名字|内容|
|-------|-------|
|Discover|可视化查询分析器|
|Visualize|Visualize|
|Dashboard|自定义主面板(添加图表)|
|Timelion|Timelion是一个kibana时间序列展示组件(暂时不用)|
|Dev Tools|Console控制台(同CURL/POSTER,操作ES代码工具,代码提示,很方便)|
|Management|管理索引库(index)、已保存的搜索和可视化结果(save objects)、设置 kibana 服务器|

Kibana基本使用

ElasticSearch本质上也是存储数据库,所有有许多的概念与MySql类似
索引(indices) ----------------- 数据库
类型(Type)-------------------- 表
文档(Document) ---------------- Row行
字段(Field) ------------------- Columns行
|概念|说明|
|-------|-------|
|索引库(indices)|indices是index的复数,代表许多的索引|
|文档(document)|存入索引库的原始数据。比如每一条商品信息,就是一个文档|
|字段(field)|文档中的属性|
|映射配置(mappings)|字段的数据类型、属性、是否索引、是否存储等特性|

  • 索引集(indices,index的复数):逻辑上的完整索引
  • 分片(shard):数据拆分后的各个部分
  • 副本(replica):每个分片的复制
    需要注意的是:ElasticSearch本身就是分布式的,因此即便你只有一个节点,ElasticSearch默认也会对你的数据进行分片和副本操作,当你想集群添加数据的时候,数据也会在新加入的节点中进行平衡

创建索引(数据库)

"number_of_shards":1 分片树
"number_of_replicas":1 副本数
kibana3.png

查询索引

kibana4.png

查询索引库是否存在

kibana5.png

删除索引

kibana6.png

创建映射关系(数据库列):需要配置一些参数

  • type:类型,可以使text、long、short、date、integer、object等
  • index:是否索引、默认为true
  • store:是否存储:默认为true
  • analyzer:分词器,这里的ik_max_word既使用ik分词器
    kibana7.png

查询映射关系

kibana8.png

添加 更新数据(我们也可以直接添加数据,这样系统会默认给我们生成一套映射关系)

如果——doc后面不知道id数,会默认生成
kibana9.png
修改使用相同的代码,修改内容即可,重点POST people/_doc/1要相同

获取数据

获取一个

libana10.png

获取全部

kibana11.png

删除数据:直接通过id即可删除

kibana12.png

查询功能:添加三个数据

POST people/_doc/1
{
  "name" : "小红",
  "age" : 18,
  "sex": "女"
}
POST people/_doc/2
{
  "name" : "小王2",
  "age" : 22,
  "sex": "男"
}
POST people/_doc/3
{
  "name" : "小男",
  "age" : 22,
  "sex": "男"
}
POST people/_doc/4
{
  "name" : "小王",
  "age" : 18,
  "sex": "女"
}

全部查询:

基本语法
GET /索引库名/_search
{
    "query":{
        "查询类型":{
            "查询条件":"查询条件值"
        }
    }
}
返回结果
time_out:是否超时
_shards:分片信息
hits:搜索结果总览对象
total:搜索到的总条数
max_score:所有结果中文档得分的最高分
hits:搜索结果的文档对象数组,每个元素是一条搜索到的文档信息
_index:索引库
_type:文档类型
_id:文档id
_score:文档得分
_source:文档的源数据

默认查询所有的people下的数据
GET people/_search
返回结果:太长,自己试

匹配查询

GET people/_search
{
  "query": {
    "match": {
      "name": "小王2"
    }
  }
}

此时会有两个返回结果“小王”、“小王2”,但是我们如果只想要小王2,那么通过通过更改关联关系即可

GET /people/_search
{
  "query": {
    "match": {
      "name": {"query": "小王2","operator": "and"}
    }
  }
}

此时就只能查到“小王2”

设置最小匹配度查询:如果只满足其中的50%q即可视为查询正确,那么“小王”和“小王2”都将被查询出来,如果设置100%那么就只能查出“小王2”

GET /people/_search
{
  "query": {
    "match": {
      "name": {"query": "小王2","minimum_should_match": "50%"}
    }
  }
}
GET /people/_search
{
  "query": {
    "match": {
      "name": {"query": "小王2","minimum_should_match": "100%"}
    }
  }
}

多字段查询:我们在sex和name字段中查询带“男”字的

GET /people/_search
{
  "query": {
    "multi_match": {
      "query": "男",
      "fields": ["name","sex"]
    }
  }
}

不管名字中有“男”字或性别是“男”的都会被查出来

词条匹配(精确查找):term查询被用于精确值匹配,这些精确值可能是数组、时间、布尔或者那些未分词的字符串,terms就是查询多个

GET /people/_search
{
  "query": {
    "terms": {
      "sex": [
        "男",
        "女"
      ]
    }
  }
}

结果过滤:如果我们查询的结果只想看到“name”("_source": "name")

GET /people/_search
{
  "query": {
    "terms": {
      "sex": [
        "男",
        "女"
      ]
    }
  },"_source": "name"
}

或者不想要谋个字段

GET /people/_search
{
  "query": {
    "terms": {
      "sex": [
        "男",
        "女"
      ]
    }
  },"_source": {
    "excludes": "sex"
  }
}