elasticsearch
全文搜索属于最常见的需求,开源的 Elasticsearch 是目前全文搜索引擎的首选。它可以快速地存储、搜索和分析海量数据。
维基百科、Stack Overflow、Github 都采用它。
Elastic 的底层是开源库 Lucene。
但是,你没法直接用 Lucene,必须自己写代码去调用它的接口。
Elastic 是 Lucene 的封装,提供了 REST API 的操作接口,开箱即用。
REST API:天然的跨平台。
动词,相当于 MySQL 中的 insert;
名词,相当于 MySQL 中的 Database
在 Index(索引)中,可以定义一个或多个类型;
类似于 MySQL 中的 Table;每一种类型的数据放在一起。
保存在某个索引(Index)下,某种类型(Type)的一个数据(Document),文档是 JSON 格式的,
Document 就像是 MySQL 中的某个 Table 里面的内容。
词 | 记录 |
---|---|
红海 | 1,2,3,4,5 |
行动 | 1,2,3 |
探索 | 2,5 |
特别 | 3,5 |
记录篇 | 4 |
特工 | 5 |
分词
:将整句分拆为单词
保存的记录
检索
:
1)、红海特工行动?
2)、红海行动?
相关性得分
:
docker pull elasticsearch:7.4.2 # 存储和检索数据
docker pull kibana:7.4.2 # 可视化检索数据
注意:elasticsearch 要和 kibana 的版本保持一致!
mkdir -p /mydata/elasticsearch/config # 在mydata文件夹下创建es的config文件夹,将docker中es的配置挂载在外部,当我们在linux虚拟机中修改es的配置文件时,就会同时修改docker中的es的配置
mkdir -p /mydata/elasticsearch/data #在mydata文件夹下创建es的data文件夹
echo "http.host:0.0.0.0" >> /mydata/elasticsearch/config/elasticsearch.yml # [http.host:0.0.0.0]允许任何远程机器访问es,并将其写入es的配置文件中
chmod -R 777 /mydata/elasticsearch/ # 保证权限问题
docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \
-e "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms64m -Xmx128m" \
-v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \
-v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.4.2
# docker run --name elasticsearch 创建一个es容器并起一个名字;
# -p 9200:9200 将linux的9200端口映射到docker容器的9200端口,用来给es发送http请求
# -p 9300:9300 9300是es在分布式集群状态下节点之间的通信端口 \ 换行符
# -e 指定一个参数,当前es以单节点模式运行
# *注意,ES_JAVA_OPTS非常重要,指定开发时es运行时的最小和最大内存占用为64M和128M,否则就会占用全部可用内存
# -v 挂载命令,将虚拟机中的路径和docker中的路径进行关联
# -d 后台启动服务
安装完 elasticsearch 后我们来启动一下,会发现使用docker ps
命令查看启动的容器时没有找到我们的 es,这是因为目前 es 的配置文件的权限导致的,因此我们还需要修改一下 es 的配置文件的权限:
[root@10 config]# cd ../
[root@10 elasticsearch]# ls
config data plugins
[root@10 elasticsearch]# cll
bash: cll: command not found
[root@10 elasticsearch]# ll
total 0
drwxr-xr-x. 2 root root 31 May 21 14:55 config
drwxr-xr-x. 2 root root 6 May 21 14:52 data
drwxr-xr-x. 2 root root 6 May 21 15:14 plugins
[root@10 elasticsearch]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
53c0e82ded18 redis "docker-entrypoint.s…" 6 weeks ago Up 4 hours 0.0.0.0:6379->6379/tcp redis
e1c1b5a6012e mysql:5.7 "docker-entrypoint.s…" 6 weeks ago Up 4 hours 0.0.0.0:3306->3306/tcp, 33060/tcp mysql
[root@10 elasticsearch]# chmod -R 777 /mydata/elasticsearch/
[root@10 elasticsearch]# ll
total 0
drwxrwxrwx. 2 root root 31 May 21 14:55 config
drwxrwxrwx. 2 root root 6 May 21 14:52 data
drwxrwxrwx. 2 root root 6 May 21 15:14 plugins
修改完文件权限后,我们使用docker start elasticsearch
再次启动 es,使用docker ps
命令查看后发现容器还是没有启动,这是问什么呢?
我们使用docker logs elasticsearch
看一下 es 的启动日志:
[root@10 elasticsearch]# docker logs elasticsearch
OpenJDK 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated in version 9.0 and will likely be removed in a future release.
2020-05-21 15:14:13,179 main ERROR No Log4j 2 configuration file found. Using default configuration (logging only errors to the console), or user programmatically provided configurations. Set system property 'log4j2.debug' to show Log4j 2 internal initialization logging. See https://logging.apache.org/log4j/2.x/manual/configuration.html for instructions on how to configure Log4j 2
Exception in thread "main" SettingsException[Failed to load settings from [elasticsearch.yml]]; nested: ParsingException[Failed to parse object: expecting token of type [START_OBJECT] but found [VALUE_STRING]];
at org.elasticsearch.common.settings.Settings$Builder.loadFromStream(Settings.java:1097)
at org.elasticsearch.common.settings.Settings$Builder.loadFromPath(Settings.java:1070)
at org.elasticsearch.node.InternalSettingsPreparer.prepareEnvironment(InternalSettingsPreparer.java:83)
at org.elasticsearch.cli.EnvironmentAwareCommand.createEnv(EnvironmentAwareCommand.java:95)
at org.elasticsearch.cli.EnvironmentAwareCommand.execute(EnvironmentAwareCommand.java:86)
at org.elasticsearch.cli.Command.mainWithoutErrorHandling(Command.java:125)
at org.elasticsearch.cli.Command.main(Command.java:90)
at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:115)
at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:92)
Caused by: ParsingException[Failed to parse object: expecting token of type [START_OBJECT] but found [VALUE_STRING]]
at org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken(XContentParserUtils.java:78)
at org.elasticsearch.common.settings.Settings.fromXContent(Settings.java:617)
at org.elasticsearch.common.settings.Settings.access$400(Settings.java:82)
上述错误是由于我之前配置elasticsearch.yml
文件的时候k-v键值对配置错误导致的,查看 yml 文件会发现我配置的内容是这样的:
http.host:0.0.0.0
修改并保存之后再次使用docker start elasticsearch
启动 es,使用docker ps
命令产看后可以看到我的 es 容器已经启动起来了:
在浏览器地址栏访问http://192.168.56.10:9200/
,可以看到 es 启动成功后返回类似下面的数据:
注意192.168.56.10
是我的linux虚拟机的地址,读者需要根据自己的虚拟机地址来进行访问
安装可视化界面
docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.56.10:9200 -p 5601:5601 \
-d kibana:7.4.2
注意,一定要将192.168.56.10
修改为自己的虚拟机地址
安装完成后在浏览器地址栏访问http://192.168.56.10:5601/
,可以看到 kibana 已经启动成功:
选择yes或no都可以:
使用我们自己的数据:
安装成功的界面:
注意:如果访问http://192.168.56.10:5601/
时出现下面的提示,可以稍等一会,可能是 kibana 还没有启动成功
也可以使用docker logs kibana
来查看一下 kibana 的启动日志,下面的日志表示 kibana 启动正常:
对 ES 的所有请求都被封装成了 REST API,因此我们可以使用 postman 来访问它。
使用 postman 或者在浏览器地址栏输入请求路径
http://192.168.56.10:9200/_cat/xxx
show databases
;
保存一个数据,保存在哪个索引
的哪个类型
下,指定用哪个唯一标识PUT customer/external/1
;
在 customer 索引下的 external 类型下保存 1 号数据为
PUT customer/external/1 |
---|
{ "name":"lohn Doe" } |
PUT 和 POST 都可以;POST 新增。如果不指定id,会自动生成 id。指定 id 就会修改这个数据,并新增版本号;PUT 可以新增也可以修改。PUT 必须指定 id;由于 PUT 需要指定 id,我们一般都用来做修改; |
在 postman 地址栏中输入 http://192.168.56.10:9200/customer/external/1
,使用 put 方法,输入参数体:
{
"name":"lohn Doe"
}
可以看到创建记录成功:
再一次发送请求后得到如下结果:
{
"_index": "customer",
"_type": "external",
"_id": "1",
"_version": 2, //注意版本号
"result": "updated",//注意结果是 update
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 1, //注意序列号
"_primary_term": 1
}
所以 put 方法既可以用来新增,也可以用来更新。
在 postman 中使用 post 方法发送 http://192.168.56.10:9200/customer/external/
请求,注意没有带 id,使用的还是上面 put 方法中的参数,
可以看到创建记录成功,es 帮我们生成了一个id:
当我们使用这个 id 再一次发送 post 请求时,就会变成更新操作:
所以 post 方法不带 id 时是新增,带 id 不存在时也是新增,带 id 且数据存在时是更新操作。
那么问题来了,put 和 post 方法有啥区别呢?如果使用 put 方法不带 id 发送请求行不行?
可以看到使用 put 方法不带 id 请求会报错,也就是说 put 是不允许不带 id 请求的,而 post 是允许的。
GET customer/external/1 |
---|
结果: { "_index": "customer", //在哪个索引 "_type": "external", //在哪个类型 "_id": "1", //记录id "_version": 4, //版本号 "_seq_no": 5, //并发控制字段,每次更新就会+1,用来做乐观锁 "_primary_term": 1, //同上,主分片重新分配,如重启,就会变化 "found": true, //表示找到了数据 "_source": { //数据内容 "name": "lohn Doe" } } |
更新携带 ?if_seq_no=0&if_primary_term=1 |
在 postman 中使用 get 方法请求 http://192.168.56.10:9200/customer/external/1
,会得到如下的结果:
{
"_index": "customer", //在哪个索引
"_type": "external", //在哪个类型
"_id": "1", //记录id
"_version": 4, //版本号
"_seq_no": 5, //并发控制字段,每次更新就会+1,用来做乐观锁
"_primary_term": 1, //同上,主分片重新分配,如重启,就会变化
"found": true, //表示找到了数据
"_source": { //数据内容
"name": "lohn Doe"
}
}
要使用乐观锁修改,我们就需要在 put 或 post 请求的路径中加上?if_seq_no=0&if_primary_term=1
字段;
我们在 postman 中使用 put 方法发送 http://192.168.56.10:9200/customer/external/1?if_seq_no=0&if_primary_term=1
请求,参数传
{
"name":"update"
}
执行更新错操作后,出现如下返回结果:
如果我们使用最新的序列号去更新,就会返回状态为 200 的更新成功的结果:
更新操作 | 参数或结论 |
---|---|
POST customer/external/1/_update |
{ "doc": { "name": "Jane Doe", "age": 20 } } |
或者POST customer/external/1 |
{ "name": "John Nash2" } |
或者PUT customer/external/1 |
{ "name": "John Nash3" } |
不同 | POST 操作会对比源文档数据,如果相同不会有什么操作,文档 version 、_seq_no 不增加; PUT 操作总会将数据重新保存并增加 version 版本; 带 _update 对比元数据如果一样就不进行任何操作。 |
看场景 | 对于大并发更新,不带update; 对于大并发查询偶尔更新,带update;对比更新,重新计算分配规则。 |
更新同时增加属性 POST customer/external/1/_update |
{ "doc": { "name": "Jane Doe", "age": 20 } } |
更新同时增加属性 PUT&POST customer/external/1 |
{ "name": "John Nash2", "age": 40 } |
使用带 _update
的 post 请求更新数据,在 postman 中使用 post 方法发送 http://192.168.56.10:9200/customer/external/1/_update
请求,参数传:
{
"doc": {
"name": "John Nash"
}
}
发送请求可以得到下面的结果,可以看到更新成功:
再次发送请求,可以看到如果数据相同,对比原来数据,与原来一样就什么都不做,_version
、_seq_no
也不会变:
使用不
带 _update
的 post 请求更新数据,在 p