1.文档与索引
常见术语 | 说明 |
---|---|
文档 Document | 用户存储在 ES 中的数据文档,ES 中存储的最小单元,类比数据库表中的一行数据 |
索引 Index | 由具有相同字段的文档列表组成,类比数据库一张表(table) |
节点 Node | 一个 ES 的运行实例,是集群的构成单元 |
集群 Cluster | 由一个或多个节点组成,对外提供服务 |
1、文档Document
Document 在 ES 中实际就是一个 Json Object,由字段(Field)组成,常见的数据类型如下:
- | 数据类型 |
---|---|
字符串 | text(会分词)、keyword(不分词,直接将输入作为一个单词输出) |
数值型 | long、integer、double、float,比较节省空间的字段有 half_float、scaled_float、short、byte |
布尔 | boolean |
日期 | date |
二进制 | binary |
范围类型 | integer_range、float_range、long_range、double_range、date_range |
复杂数据类型 | array(数组类型)、object(对象类型,可以有自己的子字段)、nested object(嵌套类型) |
地理位置数据类型 | geo_point、geo_shape |
专用类型 | ip(记录ip地址)、completion(实现自动补全)、token_count(记录分词数)、murmur3(记录字符串hash值)、percolator、join |
每一个 Document 都有唯一的 id 标识(可以自行指定或者 ES 自动生成)。每一个 Document 都有 MetaData(元数据),用于标注 Document 的相关信息:
元数据 | 说明 |
---|---|
_index | 文档所在的索引名 |
_type | 文档所在的类型名 |
_id | 文档唯一 id |
_uid | 组合 id,由 _type 和 _id 组成(6.x 开始的版本不再起作用,同 _id 一样) |
_source | 存储了文档的原始 Json 数据,可以从这里获取每个字段的内容 |
_all | 整合所有字段内容到该字段,默认禁用,也不推荐使用 |
2、索引Index
Index 中存储具有相同结构的 Document,每个 Index 都有自己的 mapping 定义,用于定义字段名和类型。
一个集群可以有多个 Index,比如:
nginx 日志存储的时候可以按照日期每天生成一个索引来存储
nginx-log-2018-01-01
nginx-log-2018-01-02
nginx-log-2018-01-03
2.Elasticsearch API
Elasticsearch 对外提供 RESTFul API :
Http Method:GET/POST/PUT/DELETE
URL基本格式:http://<ip>:<port>/<索引名>/<类型>/<文档id>
常用的两种交互方式:Curl 命令行,Kibana DevTools,这里我们使用 Kibana DevTools,以下命令全部基于 Kibana DevTools 书写,DevTools 中多个命令换一行即可同窗口展示运行。
1.分词API
ES 自带的分词器有:
分词器 | analyzer 参数 | 特性 |
---|---|---|
Standard Analyzer (默认分词器) | standard | 按词切分,支持多语言,小写处理 |
Simple Analyzer | simple | 按字母切分,小写处理 |
Whitespace Analyzer | whitespace | 按空格切分 |
Stop Analyzer | stop | stop word 指语气助词等修饰性的词语,比如 the、an、的、这 等,stop 相比 simple 多了 Stop Word 处理 |
Keyword Analyzer | keyword | 不分词,直接将输入作为一个单词输出 |
Pattern Analyzer | pattern | 通过正则表达式自定义分隔符,默认是 \W+ 即非字词的符号作为分隔符 |
Language Analyzer | language | 提供了 30+ 常见语言的分词器 |
中文分词器推荐 IK:
分词器 | analyzer 参数 | 特性 |
---|---|---|
IK Analyzer | ik_max_word | 细粒度 |
ik_smart | 粗粒度 |
1、直接指定 analyzer 进行测试
POST /_analyze
{
"analyzer":"standard", //分词器
"text":"Elasticsearch是最流行的搜索引擎" //测试文本
}
ES 返回参数:
{
"tokens" : [
{
"token" : "elasticsearch", //分词结果
"start_offset" : 0, //起始偏移
"end_offset" : 13, //结束偏移
"type" : "<ALPHANUM>",
"position" : 0 //分词位置
},
...
}
2、直接指定索引中的字段进行测试:POST /<索引名>/_analyze
POST /book/_analyze
{
"analyzer":"standard",
"text":"Elasticsearch是最流行的搜索引擎"
}
3、可以自定义分词器进行测试
POST /_analyze
{
"analyzer":"standard",
"filter":["lowercase"], //自定义analyzer, lowercase:小写
"text":"Elasticsearch是最流行的搜索引擎"
}
2.索引API
1.创建索引
1、创建索引请求:PUT /<索引名>
PUT /book
创建结构化索引:
PUT /book
{
"settings": {
"number_of_shards": "3",
"number_of_replicas": "1"
},
"mappings": {
"doc": {
"dynamic":false, //通过dynamic参数来控制字段的新增, true:(默认)允许新增字段, false:不允许新增字段(但文档可以正常写入, 就是无法对字段进行查询等操作), strict:文档不能写入
"properties": {
"title": {"type": "text","index":true}, //index字段是控制当前字段是否索引, 默认true:记录索引, false:不记录索引, 即不可搜索
"desc": {"type": "text"},
"author": {"type": "text"},
"country": {"type": "keyword"}, //keyword是不分词的一个字符串类型
"word_count": {"type": "integer"},
"date": {"type": "date", "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"}
}
}
}
}
2.自定义mapping
mapping 类似数据库中的表结构,主要作用:
- 定义索引下的字段名(Field Name)
- 定义字段的类型(比如 integer、text、keyword 等)
- 定义倒排索引相关的配置(比如是否索引、记录 position等)
properties 下字段还可以通过以下选项自定义字段:
选项 | 说明 |
---|---|
type | 类型 |
index | 控制当前字段是否索引, 默认true:记录索引, false:不记录索引, 即不可搜索 |
index_options | 用于控制倒排索引记录的内容, 有4种配置: docs:只记录文档id, freqs:记录文档id和term frequencies, position:记录文档id、term frequencies和term position, offsets:记录文档id、term frequencies、term position和character offsets。text 类型默认配置为 positions,其他默认为docs。记录内容越多,占用空间越大。 |
null_value | 当字段遇到null值时的处理策略, 默认为null, 即空值, 此时ES会忽略该值, 可以通过设定该值设定字段的默认值。 |
查询 mapping:PUT /<索引名>/_mapping
GET /book/_mapping
mapping 中的字段类型一旦设定后,禁止直接修改,因为 Lucene 实现的倒排索引生成后不允许修改。如果要修改的话,需要重新建立新的索引,然后做 reindex 操作。
multi-fields(多字段特性):允许对同一个字段采用不同的配置,比如分词,常见例子如对人名实现拼音搜索,只需要在人名中新增一个子字段为 pinyin 即可:
{
"mappings":{
"doc":{
"properties":{
"title":{
"type":"text",
"fields":{
"type":"text",
"analyzer":"pinyin"
}
}
}
}
}
}
dynamic template(动态模板):允许根据 ES 自动识别的数据类型、字段名等来动态设定字段类型,可以实现效果如下:
- 所有字符串类型都设定为keyword类型,即默认不分词
- 所有以message开头的字段都设定为text类型,即分词
- 所有以long_开头的字段都设定为long类型
- 多有自动匹配为double类型的都设定为float类似,以节省空间
{
"mappings":{
"doc":{
"dynamic_templates":[ //数组, 可指定多个匹配规则
{
"strings_as_keywords":{ //template名称, 字符串默认使用keyword类型的模板
"match_mapping_type":"string", //匹配规则
"mapping":{"type":"keyword"} //设置mapping信息
}
},
{
"message_as_text":{ //以message开头的字段都设置为text
"match_mapping_type":"string",
"match":"message*",
"mapping":{"type":"text"}
}
},
{
"double_as_float":{ //double类型设定为float,节省空间
"match_mapping_type":"double",
"mapping":{"type":"float"}
}
}
],
"properties":{}
}
}
}
匹配规则一般有如下几个参数:
匹配规则 | 说明 |
---|---|
match_mapping_type | ES自动识别的字段类型,如boolean、long、string等 |
match、unmatch | 匹配字段名 |
path_match、path_unmatch | 匹配路径 |
自定义 mapping 的操作建议:
- 写入一条文档到 ES 的临时索引中,获取 ES 自动生成的 mapping
- 修改步骤 1 得到的 mapping,自定义相关配置
- 使用步骤 2 的 mapping 创建实际所需索引
3.索引模板
索引模板(Index Template)主要用于在新建索引时自动应用预先设定的配置,简化索引创建的操作步骤:
- 可以设定索引的配置和 mapping
- 可以有多个模板,根据 order 设置,order 大的覆盖小的配置
创建索引模板请求:PUT _template/<template名称>
PUT _template/test_template
PUT _template/test_template
{
"index_patterns":["test*", "bar*"], //匹配的索引名称
"order":0, //order顺序配置
"settings":{"number_of_shards":1}, //索引的配置
"mappings":{
"doc":{
"_source":{
"enabled":false
},
"properties":{
"name":{
"type":"keyword"
}
}
}
}
}
创建索引模板后,再创建索引的时候,如果匹配上索引模板,则会直接应用这个模板的配置。
删除、查询索引模板请求:
DELETE _template/test_template
GET _template
GET _template/test_template
4.删除索引
删除索引请求:DELETE /<索引名>
DELETE /book
5.修改索引
修改索引 mappings 请求:POST /<索引名>/<类型>/_mappings
POST /book/doc/_mappings
{
"properties": {
"desc1": {"type": "text"}
}
}
6.查询索引
查询索引请求:GET /<索引名>
GET /book
查询所有索引:
GET /_cat/indices?v
除了使用 Kibana DevTools 输入命令查询外,我们还可以通过 Kibana Management 可视化查询所有索引数据。
3.文档API
1.创建文档
1、指定文档 id 插入请求:PUT /<索引名>/<类型>/<文档id>
这里这个 <类型> 默认用 doc 就可以了,因为在 ES 高级版本中会直接把 <类型> 给干掉,这个 <类型> 没必要花太多时间去理解了。
PUT /book/doc/100001
{
"title": "《细说Elasticsearch》",
"desc": "使用ES",
"author": "Tom",
"country": "China",
"word_count": 20000,
"date": "2018-01-01"
}
创建文档时,如果索引不存在,ES 会自动创建对应的 索引 和 类型,ES 返回参数:
{
"_index" : "book", //索引名
"_type" : "doc", //类型
"_id" : "100001", //文档唯一id
"_version" : 1, //文档版本,更新文档时都会更新version,乐观锁的机制
"result" : "created", //执行结果
"_shards" : { //
"total" : 2,
"successful" : 2,
"failed" : 0
},
"_seq_no" : 23,
"_primary_term" : 1
}
mapping 中未预先定义字段的情况下,ES 可以自动识别文档字段类型,从而降低用户使用成本。ES 是依靠 Json 文档的字段类型来实现自动识别字段类型,支持的类型如下:
Json类型 | ES类型 |
---|---|
null | 忽略 |
boolean | boolean |
浮点类型 | float(非double是因为float比较省空间) |
整数 | long |
object | object |
array | 由第一个非null值得类型决定 |
string | 匹配为日期则设为date类型(默认开启),匹配为数字则设为float或long类型(默认关闭),当匹配都不符合时,设为 text 类型,并附带keyword的子字段 |
2、自动生成文档 id 插入请求(不推荐用这种,这种文档 id 不可控):POST/<索引名>/<类型>
POST /book/doc
{
"title": "《细说Kibana》",
"desc": "使用Kibana控制台",
"author": "Bob",
"country": "China",
"word_count": 10000,
"date": "2018-06-01"
}
3、批量创建文档(ES 允许一次创建多个文档,从而减少网络传输开销,提升写入速率):
POST _bulk
{"index":{"_index":"book","_type":"doc","_id":"100020"}}
{"title":"《细说JVM》","desc":"深入JVM","author":"Tom","country":"China","word_count":20000,"date":"2018-01-02"}
{"index":{"_index":"book","_type":"doc","_id":"100021"}}
{"title":"《细说JVM2》","desc":"深入JVM2","author":"Tom","country":"China","word_count":20000,"date":"2018-02-02"}
{"delete":{"_index":"book","_type":"doc","_id":"100005"}}
{"update":{"_index":"book","_type":"doc","_id":"100001"}}
{"doc":{"author":"Joy"}}
注意:每条数据第一行为索引名、类型和文档id,第二行为数据内容(共两行,不能分开写,否则无法解析,除 delete(删除)只有一句之外。
2.删除文档
文档删除请求:DELETE /<索引名>/<类型>/<文档id>
DELETE /book/doc/100001
3.修改文档
文档修改请求:POST /<索引名>/<类型>/<文档id>/<动作>
POST /book/doc/100001/_update
{
"doc" : {"author": "Tony"}
}
4.文档查询API
1.根据文档id查询
根据文档id查询请求:GET /<索引名>/<类型>/<文档id>
GET /book/doc/100001
批量查询文档:
GET /_mget
{
"docs":[
{
"_index":"book", "_type":"doc", "_id":"100001"
},
{
"_index":"book", "_type":"doc", "_id":"100002"
}
]
}
2.字段类查询-全文匹配
字段类查询 | 说明 |
---|---|
全文匹配 | 针对 text 类型的字段进行全文检索,会对查询语句先进行分词处理,如 match、match_phrase 等 query 类型 |
单词匹配 | 不会对查询语句做分词处理,直接去匹配字段的倒排索引,如 term、terms、range 等 query 类型 |
查询请求:POST /<索引名>/_search
<索引名> 可以为一个或多个(POST /book,book2/_search),多个用英文逗号隔开,也可以使用通配符(POST /bo*/_search)。
1、Match Query
简单匹配查询:
POST /book/_search
{
"profile":true, //可选参数, 返回所有分片的详细信息, 供用户检查查询执行时间和其他详细信息
"query":{
"match": {"title": "细说kibana"}
}
}
ES 返回参数:
{
"took" : 2, //查询耗时,单位ms
"timed_out" : false,
"_shards" : {
"total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0
},
"hits" : { //命中的文档数据
"total" : 1, //符合条件的总文档数
"max_score" : 1.0,
"hits" : [ //返回的文档详情数据数组,默认前10个文档
{ //每一个Json Object都是一个文档
"_index" : "book", //索引名
"_type" : "doc",
"_id" : "100001", //文档唯一id
"_score" : 1.0, //文档相关性得分
"_source" : { //文档详情,原始Json数据
"title" : "《细说Elasticsearch》",
"desc" : "使用kibana", "author" : "Tom", "country" : "China",
"word_count" : 20000, "date" : "2018-01-01"
}}]
}
}
我们还可以通过增加一些参数来控制筛选的结果:
POST /book/_search
{
"profile":true,
"query":{
"match": {
"title":{
"query":"细说kibana",
"operator":"or" //控制单词间的匹配关系, 可选项为or和and, 默认or
"minimum_should_match":"2" //控制需要匹配的单词数
}
}
},
"sort": [ //排序
{"date.keyword": "desc"}, //按日期倒排(如果是text类型需要加.keyword, keyword类型直接写字段名即可)
{"_score": "desc"} , //日期相同则按得分倒排
{"_doc": "desc"} //得分相同则按文档内部id倒排
],
"from": 0, //from/size是最常用的分页方案, "from"表示开始位置, "size"表示大小
"size": 10
}
2、Match All Query
查询某索引下所有文档:
POST /book/_search
{
"query":{
"match_all": {}
},
"from": 0,
"size": 10
}
3、Match Phrase Query
短语匹配,对字段作检索, 有顺序要求:
POST /book/_search
{
"profile":true,
"query":{
"match_phrase": {"title": "hello kibana"}
}
}
我们还可以通过增加一些参数来控制筛选的结果:
POST /book/_search
{
"profile":true,
"query":{
"match": {
"title":{
"query":"hello kibana",
"slop":"1" //控制单词间的间隔, 比如设置为1则hello kibana和hello es kibana都会返回
}
}
}
}
4、Query String Query
多个字段的语法查询(查询包含 “Elasticsearch” 和 “细说”,或者是 Tom 写的书):
POST /book/_search
{
"query":{
"query_string": {
"fields":["title", "desc"],
"query": "(Elasticsearch AND 细说) OR Tom"
}
}
}
5、Simple Query String Query
类似 Query String Query,但是会忽略错误的查询语法,并且仅支持部分查询语法,常用的逻辑符号有+ 代指 AND、| 代指 OR、- 代指 NOT,不能使用 AND、OR、NOT 等关键词:
POST /book/_search
{
"query":{
"simple_query_string": {
"fields":["title", "desc"],
"query": "(Elasticsearch + 细说) | Tom"
}
}
}
3.字段类查询-单词匹配
将查询语句作为整个单词进行查询,即不对查询语句做分词处理。查询请求:POST /<索引名>/_search
1、Term Query /Terms Query
具体项查询(查询所有字数为 10000 的书):
POST /book/_search
{
"query":{
"term": {
"word_count": 10000
}
}
}
Terms Query允许一次传入多个单词进行查询:
POST /book/_search
{
"query":{
"terms": {
"word_count": [10000, 20000]
}
}
}
3、Range Query
范围查询,主要针对数值和日期类型。
查询字数在10000-20000的书, gte代表大于等于, gt代表小于, lte代表小于等于):
POST /book/_search
{
"query":{
"range": {
"word_count": {"gte": 10000, "lte": 20000}
}
}
}
查询出版时间大于等于2018-01-01的书:
POST /book/_search
{
"query":{
"range": {
"date": {"gte": "2018-01-01"}
}
}
}
相对时间查询(+1h表示加一个小时, -1d表示减一天, /d表示将时间舍入到天,包括 y-years m-months w-weeks d-days h-hours m-minutes s-seconds 等,假设now=2018-01-02 12:00:00 now+1h=2018-01-02 13:00:00 now-1h/d=2018-01-02 00:00:00 2016-01-01||+1M/d=2016-02-01 00:00:00):
POST /book/_search
{
"query":{
"range": {
"date": {"gte": "now-20y"}
}
}
}
3.复合查询
复合查询是指包含字段类查询或复合查询的类型,主要包括:constant_score query、bool query、dis_max query、function_score query、boosting query。查询请求:POST /<索引名>/_search
1、Constant Score Query
在查询过程中,除了判断文档是否满足查询条件外,ES 还会计算一个 _score 来标识匹配的程度,旨在判断目标文档和查询条件匹配的有多好。该查询将其内部的查询结果文档得分都设定为1或boost的值,多用于结合bool查询实现自定义得分:
POST /book/_search
{
"query":{
"constant_score": {
"filter": {"match": {"title": "细说"}}
}
}
}
2、Bool Query
布尔查询由一个或多个布尔子句组成,主要包含如下4个:
- | 说明 |
---|---|
filter | 只过滤符合条件的文档,不计算相关性得分。ES针对filter会有智能缓存,因此其执行效率很高。做简单匹配查询且不靠谱算分时,推荐使用filter替代query等 |
must | 文档必须符合must中的所有条件,会影响相关性得分 |
must_not | 文档必须不符合must_not中的所有条件 |
should | 文档可以符合should中的条件,会影响相关性得分 |
查询 title 是 “细说Elasticsearch” 的或者 country 是 “China” 这个关键词的,而且字数是 20000 的结果:
POST /book/_search
{
"query":{
"bool": {
"should": [
{"match": {"title": "细说Elasticsearch"}},
{"match": {"country": "China"}}
],
"filter": [
{"term": {"word_count": 20000}}
]
}
}
}
如果把 should 替换为 must 则为 “与” 的逻辑,还有 must_not 表示一定不满足。
3、Query Context VS Filter Context
上下文类型 | 执行类型 | 使用方式 |
---|---|---|
Query | 查找与查询语句最匹配的文档,对所有文档进行相关性算分并排序 | query;bool中的must和should |
Filter | 查找与查询语句相匹配的文档 | bool中的filter和must_not;constant_score中的filter |
4.Count API
1、获取符合条件的文档数,查询请求:POST /<索引名>/_count
POST /book/_count
{
"query": {
"match": {
"title": "细说"
}
}
}
5.Source Filtering
1、过滤返回结果中 _source 中的字段,查询请求:POST /<索引名>/_search
不返回字段:
POST /book/_search
{
"_source":false
}
返回部分字段:
POST /book/_search
{
"_source":["title","desc"]
}
返回部分字段(通配符):
POST /book/_search
{
"_source":{
"includes":"*t*",
"excludes":"author"
}
}