elasticsearch
elasticsearch是一个高性能高扩展性的索引系统,底层基于apache lucene。
可结合kibana工具进行可视化。
概念:
- index 索引: 类似SQL中的一张表,索引名必须是全小写单词。
- type(索引类型):设计初衷是用type对相同逻辑结构(字段名)数据的归并,一个index中只能有一种 type,在6.0版本之后被标记为过时(deprecated),在后续大版本(7.x, 8.x+)中会将被完全弃用。
- document 文档:若干个键值对的数据,类似SQL的一行记录。
检索
ES的CRUD可通过kibana工具包中的Dev Tools进行。
使用http请求实现索引查询,search操作请求基本格式为GET /<index-name>/_search
一个简单查询,无条件查文档的请求如下:
GET /myindex/_search
{"query": {"match_all": {}}
}
一个简单查询(如无条件查文档)返回的形式如下:
{"took" : 0,"timed_out" : false,"_shards" : {"total" : 5,"successful" : 5,"skipped" : 0,"failed" : 0},"hits" : {"total" : 1,"max_score" : 1.0,"hits" : [{"_index" : "myindex","_type" : "_doc","_id" : "-31ddGgBVZ-2SafgL7-y","_score" : 1.0,"_source" : {"name" : "Jack Ma3"}}]}
}
其中字段意义如下:
took
查询耗时time_out
查询是否超时_shards
查询在分片上执行的结果状态hits
查询结果hits.total
匹配的总文档数hits.max_score
结果文档的最高分值hits.hits
匹配上的文档结果集合hits.hits._index
该文档所在索引hits.hits._type
该文档所在类型hits.hits._id
文档idhits.hits._score
该文档与查询条件的匹配分值hits.hits._source
文档字段键值数据
查询请求一般格式首先是GET
的HTTP方法,请求地址形式为“//_search”,http请求携带的数据为一个json,包括"query"部分,该部分是查询条件。限定文档条数通过指定"size"实现。在分页场景中设置查询起始位置通过指定"from"实现。可通过设置"sort"指定排序条件。如:
GET /myindex/_search
{"query": {"match_all":{}},"from": 100,"size": 10,"sort":"age"
}
查询条件部分,"query",其内容为一个json对象,键是布尔值谓词或筛选谓词(filter),值是对应内容,一般是json对象。布尔值谓词包括布尔逻辑操作谓词、文档匹配谓词,前者对应布尔逻辑的与或非等,后者用于判断一个文档是否满足某种要求。
谓词是查询条件json对象的键,其值一般是json对象(或者对象数组),值内容json对象的键是谓词,从json对象顶层深入往里看,查询条件类似前缀表达式,首先看到的是谓词(operator),然后才看到谓词对应的操作数(operand)。
例:
#下列内容中“#”后内容表示注释,尽管json中没有注释的概念
{"query": {"bool": { #query下允许bool,表示一个bool条件,内容是json对象,键名是谓词,多个键是"and"关系"must": [ #must表达必须包含给定的若干个条件,类似“与 and”{"match": { #表示下面的json对象表达一个文档字段匹配条件"age": 50 #表示字段“age”值为50的文档}},{"match": {"gender": "male"}}],"must_not": { #must_not必须不匹配,可是多个条件(数组)"match": {"name": "Jack Ma"}}}}
}
有以下查询谓词:
match_all
无条件匹配所有文档。match_none
不匹配任何文档match
值内容是json对象,键是文档字段,值是目标匹配值或者带选项的值(json对象,目标值在"value"字段)。该种查询将会对字段值进行分析。ids
根据若干id查询文档。prefix
非分析性查询。查询字段的项是否具有给定前缀。match_phrase
match_phrase_prefix
term
非分析性查询。精确匹配一个项terms
类似term,匹配给定数组中任意一个值terms_set
wilcard
非分析性查询。支持通配符*
和?
的查询。查询将遍历每个项,故应避免通配符打头的查询。regexp
正则匹配。是在字段的项(terms)上的匹配,而非原文本。fuzzy
根据给定值对字段的项进行模糊查询,以编辑距离度量模糊性。bool
表明是一个布尔条件,其下是若干谓词组成的复杂条件must
必须匹配,一般对多个条件使用(数组),类似“与 AND”must_not
不匹配,相当于"非 NOT",可以对多个条件(数组)使用should
语义为“应该”匹配,“逻辑或 OR”与之接近(可指定子条件的至少匹配个数),一般对若干条件使用(或),表示匹配多个条件中的若干个条件,一般指至少匹配1个,通过与should
平行层级的键minimum_should_match
指定should中需要至少匹配的条件数量。在某些情况默认至少匹配1个。
谓词值是json对象时,其多个键名(子谓词)之间的关系基本是“与 and”关系。与"should"(平行层级)共存时,需小心"should"能匹配的条件数以及条件至少匹配数"TODO"的设置。
term:term
用于精确匹配倒排索引中的一个项(term)。也可用在范围类型数据(range data types)上。
GET _search
{"query":{"term": {"field1": "value1"}}
}GET _search
{"query": {"bool": {"should": [{"term": {"field1": {"value": "value1","boost": 2.0 #相比boost:1.0的条件重要两倍}}},{"term": {"field2": "value2"}}]}}
}
如,字段“content”的类型配置为text
,现有一文档,其该字段的值为“hello es”,在入库该文档时,由于字段类型是text,分词器会将其分为"hello"和"es"两个项(term)存入倒排索引。在用term查询时,如果查询字段"content"上的值"hello"是能检索到该文档的(或查询值为"es"也可检索到),但利用term查询字段"content"上值为"hello es"的文档,则不能命中上述文档,因为在倒排索引中没有"hello es"的项。
terms_set: terms_set
GET _search
{"query":{"terms_set": {"terms": ["value1","value2",...],"minimum_should_match_field":"<another_field>" #引用文档其他整型字段的值来指定terms中需要匹配的term的个数"minimum_should_match_script": "或者通过脚本提供需匹配个数"}}
}
match: match
会用分析器进行分词。
GET /_search{"query": {"match": {"my_field":"my_value"}}
}
前缀匹配:prefix
、match_phrase_prefix
GET _search
{"query":{"prefix": {"FIELD": "PREFIX"}}
}
模糊查询:fuzzy
在字段的项(term)上匹配
GET _search
{"query":{"fuzzy":{"field1": {"value": "my_value","fuzziness": 4 #编辑距离参数以配置模糊程度}}}
}
根据id查询多个文档:利用_mget
,索引名和类型是可选项。 GET /_mget
GET /<index>/_mget
,GET /<index>/_doc/_mget
GET /mget
{"ids":["id1", "id2"]
}
批获取 multi-get:
根据多个条件一次性获取
GET /_mget #或 /<index>/_mget 或 /<index>/_doc/_mget
{"docs": [{"_index": "myindex" #如果URL中没有<index>则必须提供;如果URL中有<index>,可不提供"_index",若提供则覆盖URL中<index>作为查询索引"_type": "" #URL中没有<type>都不要求提供"_id": "" #需提供,以匹配文档}]
}
批量操作 Bulk API:
REST API服务端点是_bulk
,请求携带数据是以行分隔的json(NDJSON),即一行一json,基本形式如下:
action_and_meta_data\n
optional_source\n
action_and_meta_data\n
optional_source\n
....
action_and_meta_data\n
optional_source\n
携带行分隔json数据的请求,其http头“content-type”的值需设置为"application/x-ndjson"。
Bulk API允许的操作有“index”、“create”、“delete”、“”、“update”。
POST /_bulk
{"index": {"_index": "myindex","_type":"", "_id": ""}} # index operation
{"field1":"val1"} # data carried by index operation
{"create": {"_index":""}
{"field1":"val1"}
{"update": {"_index":"","_type":"","_id":""}}
{"doc": {field1":"val1"}} #注意:update需指定是doc还是script方式,而不是直接提供文档结构数据
{"delete":{"_index":"", "_id":""}} #delete不携带数据体
批查询: _msearch
计数:_count
GET /.../_count # /_count /<index>/_count
{"query": ...
}
复制索引 reindex:将一个索引中的若干文档复制到另一个中,rest服务端点_reindex
。
POST _reindex
{"source":{"index": "myindex" #必须。指定源索引,单个或多个(数组)"_source": ... #可选。指定复制的字段,默认全部字段。"type": "" #可选。单个或多个(多个时对应多个索引情况)"sort": ... #排序标准,当指定size时有意义。"query": ... #可选。筛选条件"size": ... #scroll batch size},"dest": {"index": "" #必须。指定目标索引"op_type": "create" #可选参数,复制操作类型"version_type": "" #可选参数,指定版本类型}"size": <number> #可选。指定复制文档数量,默认全部。"script": ... #可选。脚本
}
立即更新 ?refresh: index,update,delete等操作的影响默认在一段时候后才会被其他(查询)操作观察到,而操作是立即返回的。即类似于多线程,一个线程对数据的更新在一定延迟后才对其他线程可见。这一行为可通过?refresh
参数控制,为false
时(默认情况),操作影响在一定延迟后可见;为true
或空时,立即对其他(查询)操作可见,当然,这需要考虑因此可能引发的性能问题;为wait_for
时,等待索引的自动刷新操作时更新数据,索引刷新动作根据index.refresh_interval
(默认1秒)周期性更新。
分页:
指定from
(默认从0开始), size
(默认10条?), sort
(默认升序):
GET /myindex/_search
{"query": {"match_all":{}},"from": 100,"size": 10,"sort":"created_time"
}
排序:
- 单字段排序,以默认升降序:
sort: "字段名"
- 单字段排序,指定升降序
{"sort": {"字段名": {#desc降序,asc升序"order": "desc" 或 "asc"}
}
- 多字段排序,以默认升降序:`sort: ["字段1", "字段2"]
- 多字段排序,每个字段指定升降序。
sort的各种形式:
{"sort" : [{ "date" : {"order" : "asc"}},"user",{ "name" : "desc" },{ "age" : "desc" },"_score"]
}
指定最小分值 min_score :
GET /_search
{"min_score": 0.8,"query": ...
}
支持多索引检索(multi index),请求地址中索引部分由多个索引以逗号拼接而成,_all
表示所有索引。多索引查询中索引名支持通配符*
,如所有以"myindex"打头的索引:myindex*
,以及通配符+排除-
,如以"myindex"打头但除了myindex1:myindex*,-myindex1
。
多索引相关参数:
ignore_unavailable
true或false,忽略不存在或已关闭(closed)的索引allow_no_indices
false或true,表示在通配符未能匹配任何索引时是否需要报异常。expand_wildcards
为其中之一none
,open
,closed
,all
,open,closed
(等同all
)。分别指禁用通配符扩展、仅扩展到open的索引、仅扩展到closed的、扩展到两种的。
时间日期相关参数……。
通用参数:
- pretty 改观返回数据的可视化
- ……
可指定需要返回的字段:
GET /myindex/_search
{"query":{"match_all":{}},"_source":["field1","field2"]
}
GET ...
{..."_source": {"include": ["profile"],"exclude": ["profile.location"]}
}
单个字段:_source: "字段名"
;多个字段: _source:["字段1","字段2"]
;不返回: _source:false
;_source_include
, _source_exclude
。
不想返回hits
数组(如在聚合查询时):设置size为0:
GET ...
{"query": ...,"size": 0,"aggs": ...
}
{"doc_fields":["field1"] }返回'not_analyzed'的字段,'text'之类的字段不允许在doc_fields中。
查询谓词可以用在"query"和"filter"两种上下文,"query"要解决的问题是“是否匹配+匹配得怎么样(即相似性、分值)”,"filter"解决的是“是否匹配”,filter更多用于结构性、可直接匹配性的字段(数值、枚举值字段)。
游标式读取:
ES支持以“游标”方式读取大批量文档,文档查询时设置以“游标”方式返回数据,ES每批次返回一定数量的文档,以及一个字符串指针,以供下次继续查询使用。
游标式读取报错:游标上下文失效?TODO
TODO _index和_type,有例子为:_index: test_20190102, _type: test_t (_t应该是配置的后缀,_index和_type有相同的前缀,_index名带了日期)
增删改
创建/替换文档: POST /<index-name>/_doc/
或指定文档id: PUT /<index-name>/_doc/<id>
,PUT时意指创建或者替换,必须指定文档id。POST时意指创建或更新,可不指定文档id。索引不存在时会自动创建索引。其中的_doc
指type,index有且仅有一个type,默认为_doc。PUT /<index>/_doc/<id>/_create
,仅作插入(创建),如果文档已存在,则报失败。
# create a document
POST /myindex/_doc
{"name":"Jack Ma"
}# create or replace a document
PUT /myindex/_doc/<id>
{"name":"Jack Ma"
}
更新文档: POST /<index-name>/_doc/<id>/_update
更新id为“1”的文档的"name"字段,并添加一个“age”和"films"字段。更新可通过文档内容或脚本完成,分别提供顶级键“doc”或“script”指定。更新请求的地址中如果没有最后的"_update",则是创建或替换(创建/替换没有顶级键"doc"或"script",而是直接提供文档内容)。
POST /myindex/_doc/1/_update
{"doc": {"name":"Stephen Chow","age":50,"films": ["喜剧之王","九品芝麻官"]}
}
也可以通过脚本更新文档。
将"age"字段值加6:
POST /myindex/_doc/1/_update
{"script:"ctx._source.age += 5"
}
删除文档:通过id删除 DELETE /<index-name>/_doc/<id>
DELETE /myindex/_doc/`
通过查询删除:DELETE /<index>/_delete_by_query
DELETE /myindex/_delete_by_query
{"query": {...}
}
通过查询条件更新:POST /<index>/_update_by_query
聚合 aggregation
GET ...
{..."aggs": ... #聚合
}
均值 avg:avg
{"aggs": {"my_return_field": { #聚合结果字段名"avg": {"field": "my_field" "missing": value-for-missing-such-field #可选。在字段缺失时的补充值}}}
}
{"aggs": {"my_avg": {"avg": {"script": "doc.my_field.value" }}}
}
加权均值: weighted_avg
,计算公式∑(value * weight) / ∑(weight)
{"aggs": {"my_return_field": {"weighted_avg": {"weight": {"field": "权值字段","missing": ... #可选。默认忽略该文档},"value": {"field": "值字段","missing": ... #可选。默认权值为1}}}}
}
数组数据+单值权重:对于一个文档的字段值为数组权重值为单值的情况,视为各自元素是相互独立的,即各自元素乘以权重,权重和(分母)是参与计算的权重的和,即元素多少个则该次计算就有多少倍权重参与计算。
#数据为:
{"g": [5,2,8],"w": 3
}
#聚合查询为:
{"aggs": {"weighted_avg": {value: {"field": "g"},"weight": {"field": "w"}}}
}
#结果为: (5*3+2*3+8*3)/(3+3+3)
最大值 max
最小值:min
和:sum
百分位: percentiles
要求数据字段类型为数值型。
{"aggs":{"my_return_field":{"percentiles": {"field": "数据字段","percents": [,,,] #可选。百分位点,默认[ 1, 5, 25, 50, 75, 95, 99 ]}}}
}
#返回
{"aggregations": {"my_return_field": {"values": [{"key": 1.0, #百分位点"value": xxx #数据点},{ "key": 99.0, "value": xxx }]}}
}
}
cardinality:cardinality
……
常用统计量:stats
返回 和(sum)、个数(count)、最小值(min)、最大值(max)、均值(avg)。
{"aggs": {"my_return_field": {"stats": {"field": "统计字段", #或通过脚本"missing": xxx #可选。}}}
}
#返回
{"aggregations": {"my_return_field": {"count": 4,"min": 20.0,"max": 80.0,"avg": 55.0,"sum": 220.0}}
}
常见统计量:extended_stats
返回 和(sum)、平方和(sum_of_squares)、个数(count)、最小值(min)、最大值(max)、均值(avg)、方差(variance)、标准差(std_deviation)等统计量。
{"aggs": {"extended_stats": {"field": "统计字段" #字段或者脚本'script'}}
}
值计数: terms
返回值以及对应计数
{"aggs":{"my_facet":{"terms"{"field": "统计字段" #在字段(field)上或使用脚本(将"field"换为"script": ...)"size": <结果条数(默认以计数降序排列)>}}}
}
返回样例
{..."aggregations": {"my_facet": {...buckets:[{"key": "词1","doc_count": <n1> #对应计数,默认按计数降序排列},{"key": "词2","doc_count": <n2>}]}}
}
经纬坐标边界查询:返回匹配文档的经纬坐标所覆盖的边界,以边界左上和右下两点坐标为代表数据返回,要求数据字段类型为geo_point
。
{"aggs":{"my_return_field":{"geo_bounds":{"field": "geo-data-field"}}}
}
经纬坐标中心点查询: geo_centroid
自定义map-reduce脚本聚合:scripted_metric
{"aggs":{"my_return_field":{"scripted_metric": {"init_script": ...,"map_script": ...,"combine_script":...,"reduce_script":...}}}
}
……
索引CURD
列举索引:GET /_cat/indices?v
或GET /_cat/indices
列举所有索引及相关信息,一索引一行,各列表示相关信息,第三列是索引名,?v
参数表示需要显示表头。
创建索引:PUT /<索引名>
,索引名必须全小,可以提供索引的字段配置。
PUT /myindex
{"mappings": {"_doc": {"properties": {"field1": {"type": "keyword"},"field2": {"type": "text" },"field3": {"type": "integer" },"field4": {"type": "date" }}}}
}
字符串形态的类型有两种,text
和keyword
,text类型的字符串将会被分析器分词,分词后一个词叫做一个'term',然后存入倒排索引。keyword类型字符串不会被分词。
删除索引:DELETE /<索引名>
,删除索引将导致其中所有文档被删除。
显示集群状态:GET /
脚本
TODO
查询里脚本的可用上下文变量
安装 配置 运行
安装elasticsearch
进入es下载页面,选择下载最新稳定版包,以6.5.4为例,下载地址 https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.5.4.tar.gz 。
解压程序包并启动单节点集群:
tar -xzvf elasticsearch-6.5.4.tar.gz
cd elasticsearch-6.5.4
bin/elsaticsearch
# bin/elasticsearch -d #(daemonize)后台运行
#后台执行ES,将pid输出到FILE
# bin/elasticsearch -d -p FILE
#通过启动命令行参数覆盖配置文件中的配置 -E参数
# bin/elasticsearch -E<key>=<value>#关停ES程序
kill -SIGTERM <pid>
ES默认在9200端口提供REST API服务。ES也提供transport api服务,该服务区别于REST API的地方主要是其数据交互是以java对象序列化/反序列化进行,该形式的API正计划被弃用。
如果报错max virtual memory areas vm.max_map_count [xxxx] is too low,可在/etc/sysctl.conf中添加vm.max_map_count=655360,然后sysctl -p
来调整相应系统参数,之后可成功启动es。
配置 elasticsearch
环境变量ES_PATH_CONF
指定ES配置文件存放目录。
配置目录可有如下配置文件:
elasticsearch.yml
jvm.options
JVM参数,一行一个参数。支持仅对特定jvm版本启用配置的语法。环境变量ES_JAVA_OPTS
配置jvm参数。log4j2.properties
日志相关
默认配置文件目录$ES_HOME/conf/。
#elasticsearch.yml
action.auto_create_index: myindex*,other_inx*,+allowed_inx*,-disallowed_inx* #对满足模式的索引名按需自动创建索引,支持通配符,支持以逗号拼接出的多个模式,“+”开头的表示允许,“-”开头的表示禁止cluster.name: #集群名,默认“elasticsearch”,同集群名的节点形成集群node.name: #节点名path:data: #索引数据存取目录,可以配成多个目录的数组logs: #日志输出目录
network.host: #服务网口,特殊值_local_, _site_, _global_
#特殊的值:${prompt.text}和${prompt.secret}表示将在控制台提示并读取输入作为对应配置值
#node.name: ${prompt.text}discovery.zen.ping.unicast.hosts: #若干<host>:<port>,<port>未指定时,将会扫描对应主机的9300~9305端口
discovery.zen.minimum_master_nodes: <数量> ##multi-search, multi-get, bulk相关
rest.action.multi.allow_explicit_index: true(默认)|false # false时,将会拒绝request-body中修改URL参数中指定的index的行为
环境变量ES_TMPDIR
配置ES临时文件目录,linux版默认/tmp
。
安装kibana
进入kibana下载页面,选择下载最新稳定版,以6.5.4为例,下载地址 https://artifacts.elastic.co/downloads/kibana/kibana-6.5.4-linux-x86_64.tar.gz 。解压程序包并启动,程序将在默认的5601端口提供Web服务。
tar -xzvf kibana-6.5.4-linux-x86_64.tar.gz
cd kibana-6.5.4-linux-x86_64
bin/kibana
配置 kibana
conf/kibana.yml
server.host: #kibana服务绑定的host, 0.0.0.0绑定到所有网络接口
server.port: