数据检索
CRUD
创建与更新
在 ElasticSearch 中,Index 这一动作类比于 CRUD 中的 Create 与 Update,当我们尝试为某个不存在的文档建立索引时,会自动根据其类似与 ID 创建新的文档,否则就会对原有的文档进行修改。ElasticSearch 使用 PUT 请求来进行 Index 操作,你需要提供索引名称、类型名称以及可选的 ID,格式规范为 :http://localhost:9200/<index>/<type>/[<id>]
。其中索引名称可以是任意字符,如果 ElasticSearch 中并不存在该索引则会自动创建。类型名的原则很类似于索引,不过其与索引相比会指明更多的细节信息:
- 每个类型有自己独立的 ID 空间
- 不同的类型有不同的映射 (Mappings),即不同的属性 / 域的建立索引的方案
- 尽可能地在一起搜索请求中只对某个类型或者特定的类型进行搜索
典型的某个 Index 请求为
curl -XPUT "http://localhost:9200/movies/movie/1" -d'
{
"title": "The Godfather",
"director": "Francis Ford Coppola",
"year": 1972
}'
ElasticSearch 仅会允许版本号高于原文档版本号的修改发生。注意,如果你并没有提供文档编号,那么应该使用 POST 方法来创建新的索引
POST /website/blog/
{
"title": "My second blog entry",
"text": "Still trying this out...",
"date": "2014/01/01"
}
Search | 搜索
ElasticSearch 为我们提供了通用的_bulk
端点来在单请求中完成多文档创建操作,不过这里为了简单起见还是分为了多个请求进行执行。ElasticSearch 中搜索主要是基于_search
这个端点进行的,其标准请求格式为 :<index>/<type>/_search
,其中 index 与 type 都是可选的。换言之,我们可以以如下几种方式发起请求
- http://localhost:9200/_search - 搜索所有的 Index 与 Type
- http://localhost:9200/movies/_search - 搜索 Movies 索引下的所有类型
- http://localhost:9200/movies/movie/_search - 仅搜索包含在 Movies 索引 Movie 类型下的文档
全文搜索
ElasticSearch 的 Query DSL 为我们提供了许多不同类型的强大的查询的语法,其核心的查询字符串包含很多查询的选项,并且由 ElasticSearch 编译转化为多个简单的查询请求。最简单的查询请求即是全文检索,譬如我们这里需要搜索关键字 :kill
:
curl -XPOST "http://localhost:9200/_search" -d'
{
"query": {
"query_string": {
"query": "kill"
}
}
}'
指定域搜索
在上文简单的全文检索中,我们会搜索每个文档中的所有域。而很多时候我们仅需要对指定的部分域中文档进行搜索操作,譬如我们要搜索仅在标题中出现ford
字段的文档
curl -XPOST "http://localhost:9200/_search" -d'
{
"query": {
"query_string": {
"query": "ford",
"fields": ["title"]
}
}
}'
Geo
PUT /my_locations
{
"mappings": {
"location": {
"properties": {
"pin": {
"properties": {
"location": {
"type": "geo_point"
}
}
}
}
}
}
}
PUT /my_locations/location/1
{
"pin" : {
"location" : {
"lat" : 40.12,
"lon" : -71.34
}
}
}
GET /my_locations/location/_search
{
"query": {
"bool" : {
"must" : {
"match_all" : {}
},
"filter" : {
"geo_distance" : {
"distance" : "200km",
"pin.location" : {
"lat" : 40,
"lon" : -70
}
}
}
}
}
}
ElasticSearch 是一个基于 Lucene 的搜索服务器;它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful web 接口。根据其官方定义,我们可以将 ElasticSearch 中的术语组件与 MySQL 进行横向对比:
MySQL => Databases => Tables => Columns/Rows
Elasticsearch => Indices => Types => Documents with Properties
基本的术语名词解释如下:
- 索引 / Index: 类似于 MySQL 中的数据库;
-
类型 / Type: 类似于 MySQL 中的表,我们可以为 Type 定义相对应的 映射 / Mappings ( 类似于 MySQL 中的 Schema ) 以优化索引性能;
-
文档 / Document: 类似于 MySQl 中的记录,是信息聚合的最小单元。
与集群相关的名词还包括:
- 集群 / Cluster: ElastichSearch 可以作为一个独立的搜索服务器工作,也可以在多台协同工作的服务器上运行,统称为一个集群,其中有一台被作为 Master,其他为 Slave;
-
节点 / Node: 一般来说一个机器部署一个 Node。
-
分片 / Shard: 指的是一个 Index 分成多少份,这些 Shards 会分散到各个 Node 上面,类似于 HDFS 的文件块。
-
副本 / Replica: 副本是针对每个分片的,可以为一个分片设置多个副本,分布在不同的节点上,即是容错,也可以提高查询任务的性能,原理同 HDFS 的文件块副本机制。
鉴于 Logstash 更多的关注于日志聚合,因此将 ElasticSearch 与 Kibana 剥离部署。如果有对于 Linux 命令不太熟悉的,可以参考 Linux DevOps 中常用命令与技巧清单。
单机配置
ElasticSearch 与 Kibana 的安装还是较为方便的,直接下载 jar 包运行即可,具体过程可以查看官方指南;不过自 5.x 版本之后,ElasticSearch 会在启动时进行系统检测,可能报的异常与解决方案如下所示:
# ElasticSearch 不允许以 root 用户运行,需要创建并且切换用户
useradd elastic
su elastic
# 以 root 用户设置文件最大描述符
# max file descriptors [8192] for elasticsearch process is too low, increase to at least [65536]
$ sudo ulimit -n 65536
# 修改 MMap
$ sudo sysctl -w vm.max_map_count=262144
# max size virtual memory [10018979840] for user [elastic] is too low, increase to [unlimited]
$ vim /etc/security/limits.conf
* hard memlock unlimited
* soft memlock unlimited
* hard nofile 65536
* soft nofile 65536
* - as unlimited
CRUD
Query: 搜索
# 简单查询
GET _search
{
"query": {
"match": {
"${FIELD}": "${TEXT}"
}
}
}
# 复杂查询
GET _search
{
"query": {
"match": {
"${FIELD}": {
"query": "${TEXT}",
"${OPTION}": "${VALUE}"
}
}
}
}
# 多重匹配
"multi_match": {
"query": "Elastic",
"fields": ["user.*", "title^3"],
"type": "best_fields"
}
# 布尔值计算
"bool": {
"must": [],
"must_not": [],
"filter": [],
"should": [],
"minimum_should_match" : 1
}
# 范围查询
"range": {
"age": {
"gte": 10,
"lte": 20,
"boost": 2
}
}
针对于复杂查询,ElasticSearch 还提供了 QueryString 查询格式:
# 默认查询全部属性
GET /_search?q=pony
# 操作符
GET /_search?q=title:(joli OR code) AND author:"Damien Alexandre"^2
# 通配符或者特殊字符
GET /_search?q=_exists_:title OR title:singl? noneOrAnyChar*cter
# 模糊搜索与范围搜索
GET /_search?q=title:elastichurch~3 AND date:[2016-01-01 TO 2018-12-31]
# Query DSL