ElasticSearch从0到集群高可用实战

(1)ElasticSearch
简称ES,是用java开发并且是当前最流行的开源的企业级搜索引擎。能够达到近实时搜索,稳定,可靠,快速,安装使用方便。
客户端支持Java、.NET(C#)、PHP、Python、Ruby等多种语言。

(2)ElasticSearch与Lucene的关系
Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库(框架)
但是想要使用Lucene,必须使用Java来作为开发语言并将其直接集成到你的应用中,并且Lucene的配置及使用非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的。
Lucene缺点:
I、只能在Java项目中使用,并且要以jar包的方式直接集成项目中
II、使用非常复杂-创建索引和搜索索引代码繁杂
III、不支持集群环境-索引数据不同步(不支持大型项目)
IV、索引数据如果太多就不行,索引库和应用所在同一个服务器,共同占用硬盘.共用空间少。
上述Lucene框架中的缺点,ES全部都能解决。ES是基于Lucene开发的。

(3)ES vs Solr比较
当单纯的对已有数据进行搜索时,Solr更快。
当实时建立索引时, Solr会产生io阻塞,查询性能较差, Elasticsearch具有明显的优势。
I、Solr 利用 Zookeeper 进行分布式管理,而Elasticsearch 自身带有分布式协调管理功能。
II、Solr 支持更多格式的数据,比如JSON、XML、CSV,而 Elasticsearch 仅支持json文件格式。
III、Solr 在传统的搜索应用中表现好于 Elasticsearch,但在处理实时搜索应用时效率明显低于 Elasticsearch。
IV、Solr 是传统搜索应用的有力解决方案,但 Elasticsearch更适用于新兴的实时搜索应用。

(4)ES vs 关系型数据库


(5)什么是全文检索
全文检索是指:

  • 通过一个程序扫描文本中的每一个单词,针对单词建立索引,并保存该单词在文本中的位置、以及出现的次数
  • 用户查询时,通过之前建立好的索引来查询,将索引中单词对应的文本位置、出现的次数返回给用户,因为有了具体文本的位置,所以就可以将具体内容读取出来了

(6)分词原理之倒排索引



就是先对数据进行分词,index是记录序号,然后在对数据进行去重,然后倒排索引(从值找到主键,正排索引是从主键找到值)
例如这时搜索hello is elasticsearch,就会先进行分词,得到hello、is、ElasticSearch,然后hello对应是(1,2),is对应是(3),ElasticSearch对应是(2,3),这样就能找出原数据

(7)ElasticSearch中的核心概念

  • 索引 index
    一个索引就是一个拥有几分相似特征的文档的集合。比如说,可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引。类似于数据库的database。
    一个索引由一个名字来标识(必须全部是小写字母的),并且当我们要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。
  • 映射 mapping
    ElasticSearch中的映射(Mapping)用来定义一个文档mapping是处理数据的方式和规则方面做一些限制,如某个字段的数据类型、默认值、分词器、是否被索引等等,这些都是映射里面可以设置的。类似于数据库的schema。
  • 字段Field
    相当于是数据表的字段|列
  • 字段类型 Type
    每一个字段都应该有一个对应的类型,例如:Text、Keyword、Byte等
  • 文档 document
    一个文档是一个可被索引的基础信息单元,类似一条记录。文档以JSON(Javascript Object Notation)格式来表示;
  • 集群 cluster
    一个集群就是由一个或多个节点组织在一起,它们共同持有整个的数据,并一起提供索引和搜索功能
  • 节点 node
    一个节点是集群中的一个服务器,作为集群的一部分,它存储数据,参与集群的索引和搜索功能
    一个节点可以通过配置集群名称的方式来加入一个指定的集群。默认情况下,每个节点都会被安排加入到一个叫做“elasticsearch”的集群中,这意味着,如果在网络中启动了若干个节点,并假定它们能够相互发现彼此,它们将会自动地形成并加入到一个叫做“elasticsearch”的集群中,在一个集群里,可以拥有任意多个节点。而且,如果当前网络中没有运行任何Elasticsearch节点,这时启动一个节点,会默认创建并加入一个叫做“elasticsearch”的集群。
  • 分片
    一个索引可以存储超出单个结点硬件限制的大量数据。比如,一个具有10亿文
    档的索引占据1TB的磁盘空间,而任一节点都没有这样大的磁盘空间;或者单个节点处理搜索请求,响应太慢。
    为了解决这个问题,Elasticsearch提供了将索引划分成多份的能力,这些份就叫
    做分片。
    当创建一个索引的时候,可以指定你想要的分片的数量。
    每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。
    分片很重要,主要有两方面的原因:
    ①允许水平分割/扩展你的内容容量
    ②允许在分片之上进行分布式的、并行的操作,进而提高性能/吞吐量
    至于一个分片怎样分布,它的文档怎样聚合回搜索请求,是完全由Elasticsearch管理的,对于作为用户来说,这些都是透明的。
  • 副本
    在一个网络/云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了,这种情况下,有一个故障转移机制是非常有用并且是强烈推荐的。为此目的,Elasticsearch允许你创建分片的一份或多份拷贝,这些拷贝叫做副本分片,或者直接叫副本。
    副本之所以重要,有两个主要原因:
    1、在分片/节点失败的情况下,提供了高可用性。
    1.1、注意到复制分片从不与原/主要(original/primary)分片置于同一节点上是非常重要的。
    2、扩展搜索量/吞吐量,因为搜索可以在所有的副本上并行运行
    2.1、每个索引可以被分成多个分片。一个索引有0个或者多个副本。
    2.2、一旦设置了副本,每个索引就有了主分片和副本分片,分片和副本的数量可以在索引创建的时候指定。
    2.3、在索引创建之后,可以在任何时候动态地改变副本的数量,但是不能改变分片的数量。

(8)安装ElasticSearch
I、创建普通用户
因为ES不能使用root用户来启动,必须使用普通用户来安装启动。这里我们创建一个普通用户以及定义一些常规目录用于存放我们的数据文件以及安装包等。

先创建组, 再创建用户:
1)创建 elasticsearch 用户组
[root@localhost ~]# groupadd elasticsearch

2)创建用户 lyc 并设置密码
[root@localhost ~]# useradd lyc
[root@localhost ~]# passwd lyc

3)# 创建es文件夹,
并修改owner为lyc用户
mkdir ‐p /usr/local/es

4)用户lyc 添加到 elasticsearch 用户组
[root@localhost ~]# usermod ‐G elasticsearch lyc
[root@localhost ~]# chown ‐R lyc /usr/local/es/elasticsearch‐7.6.1

5)设置sudo权限
#为了让普通用户有更大的操作权限,我们一般都会给普通用户设置sudo权限,方便普通用户的操作
#三台机器(集群)使用root用户执行visudo命令然后为lyc用户添加权限
[root@localhost ~]# visudo

#在root ALL=(ALL) ALL 一行下面
#添加lyc用户 如下:
lyc ALL=(ALL) ALL

#添加成功保存后切换到lyc用户操作

[root@localhost ~]# su lyc
[lyc@localhost root]$

II、修改elasticsearch.yml
继续使用lyc用户来进行修改(注意,这里最好不要复制文字,自己手敲,因为我发现编码有点问题,最终在同一级出现了两个看起来一样名字的目录)

cd /usr/local/es/elasticsearch‐7.6.1/config
mkdir ‐p /usr/local/es/elasticsearch‐7.6.1/log
mkdir ‐p /usr/local/es/elasticsearch‐7.6.1/data
创建这两个文件夹,下面配置用到
yml修改方法,去掉前面的#号,然后修改值,没有的键就在最后追加
vim elasticsearch.yml
cluster.name: my‐application
node.name: node1.lyc.cn
path.data: /usr/local/es/elasticsearch‐7.6.1/data
path.logs: /usr/local/es/elasticsearch‐7.6.1/log
network.host: 0.0.0.0
http.port: 9200
discovery.seed_hosts: ["ES服务器的IP"]
cluster.initial_master_nodes: ["ES服务器的IP"]
bootstrap.system_call_filter: false
bootstrap.memory_lock: false
http.cors.enabled: true
http.cors.allow‐origin: "*"

III、修改jvm.option
修改jvm.option配置文件,调整jvm堆内存大小
node1.lyc.cn使用lyc用户执行以下命令调整jvm堆内存大小,每个人根据自己服务器的内存大小来进行调整。

cd /usr/local/es/elasticsearch‐7.6.1/config
vim jvm.options
‐Xms2g
‐Xmx2g

IV、修改系统配置,解决启动时候的问题
由于现在使用普通用户来安装es服务,且es服务对服务器的资源要求比较多,包
括内存大小,线程数等。所以我们需要给普通用户解开资源的束缚
遇到:
问题错误信息描述: max file descriptors [4096] for elasticsearch process likely too low, increase to at least [65536]
解决:

ES因为需要大量的创建索引文件,需要大量的打开系统的文件,所以我们需要解
除linux系统当中打开文件最大数目的限制,不然ES启动就会抛错
三台机器(集群)使用lyc用户执行以下命令解除打开文件数据的限制
sudo vi /etc/security/limits.conf
添加如下内容: 注意*不要去掉了
* soft nofile 65536
* hard nofile 65536
此文件修改后需要重新登录用户,才会生效

遇到:
问题错误信息描述 max number of threads [1024] for user [es] likely too low, increase to at least [4096]
解决:

修改普通用户可以创建的最大线程数
max number of threads [1024] for user [es] likely too low, increase to
at least [4096]原因:无法创建本地线程问题,用户最大可创建线程数太小解决
方案:修改90-nproc.conf 或20-nproc.conf配置文件。
三台机器(集群)使用lyc用户执行以下命令修改配置文件
1 Centos6
2 sudo vi /etc/security/limits.d/90‐nproc.conf
3 Centos7
4 sudo vi /etc/security/limits.d/20‐nproc.conf
找到如下内容:
* soft nproc 1024#修改为
* soft nproc 4096

遇到:
错误信息描述: max virtual memory areas vm.max_map_count [65530] likely too low, increase to at least [262144]
解决:

调大系统的虚拟内存
原因:最大虚拟内存太小
每次启动机器都手动执行下。
三台机器(集群)执行以下命令
编辑 /etc/sysctl.conf,追加以下内容:vm.max_map_count=655360保存后,执行:sysctl ‐p

备注:以上三个问题解决完成之后,重新连接secureCRT或者重新连接xshell生效

V、关闭防火墙
不然端口访问不了

关闭Linux防火墙
永久性生效,重启后不会复原
开启: chkconfig iptables on
关闭: chkconfig iptables off
即时生效,重启后复原
开启: service iptables start
关闭: service iptables stop
centos7关闭防火墙 systemctl stop firewalld.service

VI、启动ES服务
三台机器(集群)使用lyc用户执行以下命令启动es服务
cd /usr/local/es/elasticsearch-7.6.1/bin
后台启动ES
./elasticsearch -d
启动成功之后jsp即可看到es的服务进程,并且访问页面
http://192.168.21.128:9200
能够看到es启动之后的一些信息
注意:如果哪一台机器服务启动失败,那么就到哪一台机器的 /usr/local/es/elasticsearch-7.6.1/log 这个路径下面去查看错误日志


(9)安装Kibana客户端
ES是一个服务,类似mysql,我们会安装Navicat客户端来方便使用,所有这里安装Kibana客户端帮助我们使用。

前面第8步的时候,只给了普通用户的elasticsearch‐7.6.1目录权限,这里再修改一下目录权限
chown ‐R lyc /usr/local/es
1)下载Kibana放之/usr/local/es目录中
2)解压文件:tar -zxvf kibana-X.X.X-linux-x86_64.tar.gz
3)进入/usr/local/es/kibana-X.X.X-linux-x86_64/config目录
4)使用vi编辑器:vi kibana.yml
server.port: 5601
server.host: "服务器IP"
elasticsearch.hosts: ["http://IP:9200"] #这里是elasticsearch的访问地址
5)启动Kibana
./usr/local/es/kibana-7.6.1-linux-x86_64/bin/kibana
推荐后台启动:
nohup ./kibana &
6)访问Kibana
http://ip:5601/app/kibana

使用:
可以点击Console



输入以下内容并运行


(10)安装IK分词器
ES的默认分词器对中文不好,所以安装IK
IK版本尽量和ES版本一致

切换到lyc用户,并在es的安装目录下/plugins创建ik
mkdir ‐p /usr/local/es/elasticsearch‐7.6.1/plugins/ik
 将下载的ik分词器上传并解压到该目录
cd /usr/local/es/elasticsearch‐7.6.1/plugins/ik
解压 elasticsearch‐analysis‐ik‐7.6.1.zip(这个是zip包,在windows解压然后放进centos吧)
重启Elasticsearch
先kill在 ./ElasticSearch -d

ES的默认分词设置是standard,这个在中文分词时就比较尴尬了,会单字拆分,比如我搜索关键词“清华大学”,这时候会按“清”,“华”,“大”,“学”去分词,然后搜出来的都是些“清清的河水”,“中华儿女”,“地大物博”,“学而不思则罔”之类的莫名其妙的结果,这里我们就想把这个分词方式修改一下,于是呢,就想到了ik分词器,有两种ik_smart和ik_max_word。
ik_smart会将“清华大学”整个分为一个词,而ik_max_word会将“清华大学”分为“清华大学”,“清华”和“大学”,按需选其中之一就可以了。

POST _analyze
{
  "analyzer":"standard",
  "text":"我爱你中国"
}

POST _analyze
{
  "analyzer": "ik_smart",
  "text": "中华人民共和国"
}
#ik_smart:会做最粗粒度的拆分

POST _analyze
{
  "analyzer":"ik_max_word",
  "text":"我爱你中国"
}
#ik_max_word:会将文本做最细粒度的拆分

通过效果可以看出,ik_max_word是比较好的,修改默认分词方法

修改默认分词方法(这里修改school_index索引的默认分词为:ik_max_word):
PUT /school_index
{
  "settings" : {
    "index" : {
      "analysis.analyzer.default.type": "ik_max_word"
    }
  }
}

(11)ES的基本操作
ES的格式是json,下面的命令直接在kibana的console中执行即可。
回忆一下ES的端口是9200,Kibana的端口是5601
I、创建索引
PUT /es_db

II、查询索引
GET /es_db

III、删除索引
DELETE /es_db

IV、添加文档
PUT /索引名称/类型/id


注意:ES版本变化很大,要看自己对应版本的语法

V、修改文档
同上,使用PUT

VI、查询文档
GET /索引名称/类型/id
GET /es_db/_doc/1

VII、删除文档
DELETE /索引名称/类型/id
DELETE /es_db/_doc/1

VIII、查询当前类型中的所有文档
GET /索引名称/类型/_search
GET /es_db/_doc/_search

IX、条件查询
GET /索引名称/类型/_search?q=*:***
GET /es_db/_doc/_search?q=age:28

X、范围查询,TO必须大写
GET /索引名称/类型/_search?q=***[** TO **]
GET /es_db/_doc/_search?q=age[25 TO 27]

XI、根据多个ID进行批量查询
GET /索引名称/类型/_mget
GET /es_db/_doc/_mget

XII、查询年龄小于等于28岁的
GET /索引名称/类型/_search?q=***:<=**
GET /es_db/_doc/_search?q=age:<=28

XIII、分页查询
GET /索引名称/类型/_search?q=***[** TO **]&from=*&size=*
GET /es_db/_doc/_search?q=age[25 TO 27]&from=0&size=1

XIV、对查询结果只输出某些字段
GET /索引名称/类型/_search?_source=字段,字段
GET /es_db/_doc/_search?_source=name,age

XV、对查询结果排序
GET /索引名称/类型/_search?sort=字段:desc
GET /es_db/_doc/_search?sort=age:desc

(12)DSL语言高级查询
ES提供了强大的查询语言(DSL),它可以允许我们进行更加强大、复杂的查
询,Elasticsearch DSL中有Query与Filter两种

  • Query方式查询,会在ES中索引的数据都会存储一个_score分值,分值越高就代表越匹配。另外关于某个搜索的分值计算还是很复杂的,因此也需要一定的时间。
  • Filter过滤器方式查询,它的查询不会计算相关性分值,也不会对结果进行排序, 因此效率会高一点,查询的结果可以被缓存。

I、精确查询 term
term查询不会对字段进行分词查询,会采用精确匹配

POST /es_db/_doc/_search
{
  "query": {
    "term": {
      "name": "广东广州"
    }
  }
}

广东广州不会再分词

II、模糊查询 match
match会根据该字段的分词器,进行分词查询

POST /es_db/_doc/_search
{
  "query": {
    "match": {
      "address": "广东广州"
    }
  }
}

广东广州就会分词,取决于使用的是什么分词器,然后按匹配度高(得分高)的排序


III、多字段模糊匹配查询与精准查询 multi_match

POST /es_db/_doc/_search
{
  "query":{
    "multi_match":{
      "query":"张三",
      "fields":["address","name"]
    }
  }
}

IV、未指定字段条件查询 query_string

POST /es_db/_doc/_search
{
  "query":{
    "query_string":{
      "query":"(广州) OR 长沙"
    }
  }
}

V、指定字段条件查询 query_string

POST /es_db/_doc/_search
{
  "query":{
    "query_string":{
      "query":"admin OR 长沙",
      "fields":["name","address"]
    }
  }
}

VI、范围查询
部分字段含义:
range:范围关键字
gte 大于等于
lte 小于等于
gt 大于
lt 小于
now 当前时间

POST /es_db/_doc/_search
{
  "query" : {
    "range" : {
      "age" : {
        "gte":25,
        "lte":28
      }
    }
  }
}

VII、分页、输出字段、排序综合查询

POST /es_db/_doc/_search
{
  "query" : {
    "range" : {
      "age" : {
        "gte":25,
        "lte":28
      }
    }
  },
  "from": 0,
  "size": 2,
  "_source": ["name", "age", "book"],
  "sort": {"age":"desc"}
}

下面是filter的查询,查出来的数据得分会是0
VIII、

POST /es_db/_doc/_search
{
  "query" : {
    "bool" : {
      "filter" : {
        "term":{
          "age":25
        }
      }
    }
  }
}

bool是做组合查询的,里面可以放多个条件

(13)文档映射
ES中映射可以分为动态映射和静态映射。
动态映射:
在关系数据库中,需要事先创建数据库,然后在该数据库下创建数据表,并创建表字段、类型、长度、主键等,最后才能基于表插入数据。而Elasticsearch中不需要定义Mapping映射(即关系型数据库的表、字段等),在文档写入Elasticsearch时,会根据文档字段自动识别类型,这种机制称之为动态映射。


映射规则

静态映射:
静态映射是在Elasticsearch中也可以事先定义好映射,包含文档的各字段类型、分词器等,这种方式称之为静态映射。

动态不用定义,静态要定义。当动态映射不精准的时候,可以使用静态映射

我们并没有创建映射,但在插入数据之后,就会自动创建映射,查看映射:



设置文档映射

PUT /es_db
{
  "mappings":{
    "properties":{
      "name":{"type":"keyword","index":true,"store":true},
      "sex":{"type":"integer","index":true,"store":true},
      "age":{"type":"integer","index":true,"store":true},
      "book":{"type":"text","index":true,"store":true},
      "address":{"type":"text","index":true,"store":true}
    }
  }
}

keyword和text都是字符串类型,但他们有区别
keyword:我们插入值的时候,值不会被拆分,也就是只能精准查询,不能分词查询。能聚合、排序。
text:能模糊查询,能分词查询。不能聚合、排序。

(14)创建静态映射时指定text类型的ik分词器

PUT /es_db
{
  "mappings":{
    "properties":{
      "name":{"type":"keyword","index":true,"store":true},
      "sex":{"type":"integer","index":true,"store":true},
      "age":{"type":"integer","index":true,"store":true},
      "book":{"type":"text","index":true,"store":true,
        "analyzer":"ik_smart",
        "search_analyzer":"ik_smart"},
      "address":{"type":"text","index":true,"store":true}
    }
  }
}

index:是否需要分词。true的话就会建立索引,可以控制某个字段是否需要分词,通常就是需要搜索的才会分,不需要搜索的就不分,提高性能。


store:是否需要存储。查到的index来定位到某条数据,所以就是要先存储某条数据才会有它的index,才能通过index定位得到这条数据。所以正常来说,都是要存储的。也有不存储的情况:例如有id、名称、内容三个字段,通常内容就是不存的,让它为null,为什么不存,我们可以这样来理解,我们在商城搜索内容的时候,通常也就是搜索名称、价格等信息,并且搜索出来的结果也不会把详细信息显示出来,所以并没有搜内容这个功能,如果连内容都要搜,这样就会大量分词,又建立索引,消耗性能。搜关键字用es,再得到id搜mysql得到详细信息。

具体更多的细化字段的设置,就应该要看文档了

(15)ES集群环境搭建
三台机器:
要注意一下,三个es的cluster_uuid都不要相同,也就是不要克隆,要从一个未使用过的压缩包重新解压





三台机器的cluster.name都要相同
这里我从网上找到一个解析:

# true选主时,有可能被选为主
node.master: true
# 数据节点
node.data: true
#集群名称,所有节点集群名一样
cluster.name: ikang_cluster
#节点名称
node.name: node-206
#索引存储位置
path.data: /usr/local/soft/elasticsearch/es_data
#日志位置
path.logs: /usr/local/soft/elasticsearch/logs
#外部访问地址,可以设置成主机ip
network.host: 0.0.0.0
#外部http访问端口
http.port: 9200
#节点之间通信ip,本机ip
network.publish_host: 192.168.75.206
#节点之间通信端口
transport.tcp.port: 9300
#集群中节点,默认时9300可以忽略,
discovery.seed_hosts: ["192.168.72.206:9300", "192.168.72.207:9300", "192.168.72.208:9300"]
#初始集群主节点,可以配置多个,从中选主一个作为主
cluster.initial_master_nodes: ["node-206"]
#跨域访问配置
http.cors.enabled: true
http.cors.allow-origin: "*"

另外,需要插件方便我们查看集群的信息

(16)Elasticsearch-head插件
elasticsearch-head这个插件是es提供的一个用于图形化界面查看的一个插件工具,可以安装上这个插件之后,通过这个插件来实现我们通过浏览器查看es当中的数据。
安装elasticsearch-head这个插件这里提供两种方式进行安装,第一种方式就是自己下载源码包进行编译,耗时比较长,网络较差的情况下,基本上不可能安装成功。
第二种方式就是直接使用我已经编译好的安装包,进行修改配置即可要安装elasticsearch-head插件,需要先安装Node.js。

wget https://npm.taobao.org/mirrors/node/v8.1.0/node‐v8.1.0‐linux‐x64.tar.gz
tar ‐zxvf node‐v8.1.0‐linux‐x64.tar.gz ‐C /usr/local/es/
解压完就可以了,创建一些软连接
sudo ln ‐s /usr/local/es/node‐v8.1.0‐linux‐x64/lib/node_modules/npm/bin/npm‐cli.js /usr/local/bin/npm
sudo ln ‐s /usr/local/es/node‐v8.1.0‐linux‐x64/bin/node /usr/local/bin/node

修改环境变量
vim /etc/profile
添加
export NODE_HOME=/usr/local/es/node‐v8.1.0‐linux‐x64
export PATH=:$PATH:$NODE_HOME/bin

修改完环境变量使用source生效
source /etc/profile

验证
node ‐v
npm ‐v

安装Elasticsearch-head插件

elasticsearch-head-compile-after.tar.gz(可以github下载) 上传到node1.lyc.cn(126.128)机器的/usr/local/es 路径下面去
解压
tar ‐zxvf elasticsearch‐head‐compile‐after.tar.gz ‐C /usr/local/es/

修改Gruntfile.js
cd /usr/local/es/elasticsearch‐head
vim Gruntfile.js
找到第93行(输入:93可定位行,或者/connect搜索connect),hostname: '192.168.100.100', 修改为:对应ip,如果ip变化的,要改为域名
connect: {
  server: {
    options: {
      hostname: '192.168.126.128',
      port: 9100,
      base: '.',
      keepalive: true
    }
  }
}

修改app.js
cd /usr/local/es/elasticsearch‐head/_site
vim app.js
在Vim中输入「:4354」,定位到第4354行,修改 http://localhost:9200为http://192.168.126.128:9200

启动head服务

cd /usr/local/es/elasticsearch‐head/node_modules/grunt/bin/
前台运行:./grunt server
后台运行:nohup ./grunt server >/dev/null 2>&1 &

停止进程:
netstat ‐nltp | grep 9100
kill ‐9 pid


这图我是失败了,原因应该是我克隆虚拟机,三个es的cluster_uuid都相同
我从网上找到几个连接,大家可以看一看



起初我的做法是:

先删除es目录下的data下的nodes文件夹,然后重启es,访问ip:9200,会看到uuid是_na_,
然后访问ip:9200/_cat/nodes报错误master_not_discovered_exception,
网上说的就是把cluster.initial_master_nodes改为和node.name相同,
重启,访问ip:9200发现已经有uuid了,ip:9200/_cat/nodes也能正常访问


但还是无法查看到集群的其他节点,最后我还是通过删除之前装的es,然后再重新在三台机上安装es,正常集群

集群健康值的几种状态如下:
 绿色:最健康的状态,代表所有的分片包括备份都可用
 黄色:基本的分片可用,但是备份不可用(也可能是没有备份)
 红色:部分的分片可用,表明分片有一部分损坏。此时执行查询部分数据仍然可以查到,遇到这种情况,还是赶快解决比较好。
 灰色:未连接到elasticsearch服务
es_db那一行都是索引库的名字

上图中可以看到,有两个绿色的0,其中一个粗框,一个细边框,这是es7.x版本后,默认一个主分片,一个备份分片,在7.x之前是默认5个主分片,一个备份分片。这是默认的情况,也可以在在创建索引的时候,指定要几个主分片,几个备份分片。
假设有这样的一个情况



它是3个主分片,2个备份分片。粗框0、1、2共3个主分片,粗框0对应有两个细边框0,所以是2个备份分片。
分片的意思就理解为分布式存储,假设有6条数据,每个主分片存2条数据,012只是一些分片的下标。

(17)IK分词器细看
我们找到插件中ik目录下的config目录,然后打开看看里面的main.dic


一共有20多万条数据,ik分词器就是会根据这个文件来进行分词的,
然后在看看其他dic

很明显,ik就是依赖这些dic文件来进行分词的
然后在config目录下还有一个非dic文件IKAnalyzer.cfg.xml,打开看看

就是给我们扩展的。不过这个方法我们一般不用,因为改这个文件是需要重启es的,在集群环境下,重启是很麻烦的,最好的方法是热更新。

(18)改进IK分词器
IK分词器源码是没有热更新功能的,需要我们去修改源码
网上有很多的方法,注意不同的版本可能方法不一样,这里看一下白起的操作



在初始化的时候我们开启一个线程,用来执行远程词库的热更新,这个HotDictReloadThread是自己写的,不叫这个名字也可以。

public class HotDictReloadThread {

    private static final Logger log = ESPluginLoggerFactory.getLogger(HotDictReloadThread.class.getName());

    public void inital(){
        while(true){
            log.info("正在调用HotDictReloadThread");
            Dictionary.getSingleton().reLoadMainDict();
        }
    }
}

这里的死循环是为了让它定时去数据库获取词库。
然后ctrl进入reLoadMainDict方法,额外执行加载数据库的词库

void reLoadMainDict() {
        logger.info("start to reload ik dict.");
        // 新开一个实例加载词典,减少加载过程对当前词典使用的影响
        Dictionary tmpDict = new Dictionary(configuration);
        tmpDict.configuration = getSingleton().configuration;
        tmpDict.loadMainDict();
        tmpDict.loadStopWordDict();

        //加载远程扩展词库
        tmpDict.loadMySQLExtDict();
        //加载远程停用词库
        tmpDict.loadMySQLStopwordDict();

        _MainDict = tmpDict._MainDict;
        _StopWords = tmpDict._StopWords;
        logger.info("reload ik dict finished.");
    }

loadMySQLExtDict和loadMySQLStopwordDict都是自己实现的方法,名字随便,自己按需实现
这里展示loadMySQLExtDict的示例,自己用其他方法实现也可以的

private void loadMySQLExtDict(){
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try{
            Path file = PathUtils.get(getDictRoot(), "jdbc-reload.properties");
            props.load(new FileInputStream(file.toFile()));

            logger.info("jdbc-reload.properties");
            for (Object key : props.keySet()){
                logger.info(key + "=" + props.getProperty(String.valueOf(key)));
            }

            logger.info("query hot dict from mysql, "+props.getProperty("jdbc.reload.sql"));
            conn = DriverManager.getConnection(
                    props.getProperty("jdbc.url"),
                    props.getProperty("jdbc.user"),
                    props.getProperty("jdbc.password")
            );
            stmt = conn.createStatement();
            rs = stmt.executeQuery(props.getProperty("jdbc.reload.sql"));

            while(rs.next()){
                String theWord = rs.getString("word");
                logger.info("正在加载Mysql自定义IK扩展词库词条:"+theWord);
                _MainDict.fillSegment(theWord.trim().toCharArray());
            }

            Thread.sleep(Integer.valueOf(String.valueOf(props.get("jdbc.reload.interval"))) * 1000);
        }catch (Exception e){
            logger.error("error", e);
        }finally {
            if(rs!=null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(stmt!=null){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }

方法中要读到配置文件,在config目录下创建jdbc-reload.properties,内容如下

jdbc.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///es
jdbc.user=root
jdbc.password=xxx
jdbc.reload.sql=select xx from table where xx=xx
jdbc.reload.stopword.sql=select xx from table where xx=xx
jdbc.reload.interval=10

自己建好表,设计字段,基本就完成了
改好之后就用mvn clean package打包,按ik安装步骤扔到es插件里面就好了

你可能感兴趣的:(ElasticSearch从0到集群高可用实战)