使用kibana编写Elasticsearch操作命令语句
创建索引
创建索引相当于创建数据库。
创建索引,指定分片和副本的数量(相当于创建数据库)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#es的文档、索引的CRUD操作 #索引初始化操作 #指定分片和副本的数量 #shards一旦设置不能修改 PUT lagou { "settings": { "index":{ "number_of_shards":5, "number_of_replicas":1 } } } |
GET 查询settings
1 2 3 4 5 6 7 8 9 10 11 |
# 获取lagou索引的settings GET lagou/_settings # 获取所有索引的settings GET _all/_settings # 获取指定索引的settings(索引之间用“,”号分开) GET .kibana,lagou/_settings # 获取所有索引的信息 GET _all |
PUT 更新settings
1 2 3 4 5 |
# 更新lagou索引的settings PUT lagou/_settings { "number_of_replicas":2 } |
保存/新增文档
指定id,使用PUT
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 保存文档 # PUT 索引/type(相当于表)/id PUT lagou/job/1 { "title":"python分布式爬虫开发", "salary_min":15000, "city":"北京", "company":{ "name":"百度", "company_addr":"北京市软件园" }, "publish_date":"2017-4-16", "comments":15 } |
id自增,使用POST
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 保存文档 # 自增ID,注意使用的是post POST lagou/job/ { "title":"python django开发工程师", "salary_min":30000, "city":"北京", "company":{ "name":"美团科技", "company_addr":"北京市软件园A区" }, "publish_date":"2017-4-16", "comments":20 } |
文档插入后,可以到head插件里(http://127.0.0.1:9100/)里的“数据浏览”里,看到插入的数据:
查询文档
1 2 |
# 查询lagou的job的id为1的信息 GET lagou/job/1 |
查询到的数据这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
{ "_index": "lagou", "_type": "job", "_id": "1", "_version": 1, "found": true, "_source": { "title": "python分布式爬虫开发", "salary_min": 15000, "city": "北京", "company": { "name": "百度", "company_addr": "北京市软件园" }, "publish_date": "2017-4-16", "comments": 15 } } |
还可以字段过滤查询:
1 2 |
# 查询字段过滤 GET lagou/job/1?_source=title,city |
查到的结果是:
1 2 3 4 5 6 7 8 9 10 11 |
{ "_index": "lagou", "_type": "job", "_id": "1", "_version": 1, "found": true, "_source": { "city": "北京", "title": "python分布式爬虫开发" } } |
修改文档
覆盖式修改,使用PUT
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 修改文档(覆盖) # put修改文档要指明id # put是覆盖修改,把全部内容都覆盖 PUT lagou/job/1 { "title":"python分布式爬虫开发", "salary_min":15000, "company":{ "name":"百度", "company_addr":"北京市软件园" }, "publish_date":"2017-4-16", "comments":15 } |
增量式修改,使用POST
1 2 3 4 5 6 7 8 9 10 |
# 修改文档(增量) # post修改文档要指明id,并后加_update关键字 # put是覆盖修改,把全部内容都覆盖 # 里面的doc,不能少,doc里指定修改的字段 POST lagou/job/1/_update { "doc": { "comments":20 } } |
删除
1 2 3 4 5 6 7 8 9 10 |
#删除 # 删除指定文档 DELETE lagou/job/1 # 删除type,新版不支持 DELETE lagou/job # 删除索引 DELETE lagou |
批量操作
如果命令一条条的执行,那么,每执行一条命令,就需要建立一次http连接(elasticsearch是C/S架构),每次都要经历三次握手、四次分手的过程,遇上数量很多的命令,那么效率就会降低。所以,elasticsearch为了解决这个问题,提供了一些批量操作的命令。
批量获取(get)
批量获取使用命令:GET _mget
有一个索引testdb如下:
代码使用如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# "docs",不可少 # "_index":"testdb", 查询的数据库 # "_type":"job1", 查询的表 # "_id":1, 查询的id #docs里,一个{},是一次查询 GET _mget { "docs":[ { "_index":"testdb", "_type":"job1", "_id":1 }, { "_index":"testdb", "_type":"job2", "_id":2 } ] } |
如果是取同一个索引(数据库)下的数据,可以把索引(数据库)抽出来:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# 只取一个索引下的数据,可以把索引写在_mget的前面 # 这样就不用每个都写"_index":"testdb" GET testdb/_mget { "docs":[ { "_type":"job1", "_id":1 }, { "_type":"job2", "_id":2 } ] } |
同理,我们也可以把类型(表)提到_mget前,表示只对这个类型(表)查询数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 只取某个索引的某个类型下的数据, # 可以把类型写在_mget的前面 # 这样就不用每个都写 "_type":"job1" GET testdb/job1/_mget { "docs":[ { "_id":1 }, { "_id":2 } ] } |
上面的id也可以使用“ids”来简写:
1 2 3 4 5 6 |
# 指定了索引和类型,通过id获取指定数据 # 可以使用"ids",取代"docs" GET testdb/job1/_mget { "ids":[1,2] } |
bulk 批量操作
批量导入可以合并多个操作,比如index、delete、update、create等等。可以让我们把多个的这些操作合并,一次提交。也可以帮助我们从一个索引导入到另一个索引。
需要注意的是,每一条数据都由两行构成(delete除外),其他的命令比如index和create都是由元信息行和数据行组成,update比较特殊,它的数据行可能是“doc”也可能是“upsert”或者“script”。
每一条数据都由两行构成:
1 2 |
{"index":{"_index":"lagou","_type":"job","_id":"1"}} #这一行告诉要操作的目标 {"field":"value1"} # 这一行是要操作的数据 |
{"index":{"_index":"lagou","_type":"job","_id":"1"}}
“index”为操作类型,“_index”:填写要索引名,“_type”:填写要类型名,“_id”:填写id
创建索引(index):
1 2 |
{"index":{"_index":"test","_type":"type1","_id":"1"}} # 这一行,指明 创建索引的目标 {"field1":"value1"} # 这一行,创建索引时的数据 |
示例:
1 2 3 4 5 |
POST _bulk {"index":{"_index":"lagou","_type":"job","_id":"1"}} {"title":"python分布式爬虫开发","salary_min":15000,"city":"北京","company":{"name":"百度","company_addr":"北京市软件园"},"publish_date":"2017-4-16","comments":15} {"index":{"_index":"lagou","_type":"job2","_id":"2"}} {"title":"python django开发","salary_min":30000,"city":"成都","company":{"name":"阿里巴巴","company_addr":"北京市软件园B区"},"publish_date":"2017-4-18","comments":50} |
注意:使用 _bulk批量操作的数据,都是要一行一行的写,不能美化成json那样的格式,否则会报错。
增加数据(create):
1 2 |
{"create":{"_index":"test","_type":"type1","_id":"3"}} # 这一行,指明 增加的目标 {"field1":"value3"} # 这一行,增加的数据 |
示例:
1 2 3 |
POST _bulk {"create":{"_index":"lagou","_type":"job","_id":"3"}} {"title":"python 数据分析开发","salary_min":10000} |
更新数据(update):
1 2 |
{"update":{"_index":"test","_type":"type1","_id":"3"}} # 这一行,指明 更新的目标 {"doc":{"field2":"value2"}} # 这一行,更新的数据 |
示例:
1 2 3 |
POST _bulk {"update":{"_index":"lagou","_type":"job","_id":"3"}} {"doc":{"title":"python 数据分析实习","salary_min":9000}} |
删除数据(delete):
1 |
{"delete":{"_index":"test","_type":"type1","_id":"3"}}# 删除只有一行,指明 删除的目标 |
示例:
1 2 |
POST _bulk {"delete":{"_index":"lagou","_type":"job","_id":"3"}} |
bulk会把这些命令发送到一个节点,然后由这个节点解析元数据(也就是类似这个:{"_index":"lagou","_type":"job","_id":"3"}
),然后分发到其他节点的分片,进行操作,等到所有的命令执行完成以后,才统一返回结果。
需要注意的是:但bulk处理的数据比较大,会chunk(分片)传输,因为数据量比较大,会有一定的延迟,所以,不要一次性提交的数据过多。
mapping映射管理
当我们创建索引的时候,可以预先定义字段的类型以及相关属性。这是针对创建type(对应表)的时候生效,为字段指定属性类型,比如:title字段指定为字符串类型,那么title字段就只能存放字符串。还可指定title字段的属性,是否可以被Elasticsearch搜索。
默认情况下,Elasticsearch会根据JSON源数据的基础类型猜测你想要的字段映射。将输入的数据转变成可搜索的索引项。Mapping就是我们自己定义的字段的数据类型,同时告诉Elasticsearch如何索引数据以及是否可以被搜索。
它的作用,会让索引建立的更加细致和完善。
内置类型
- string类型:text,keyword(string类型在ES5开始已经废弃)。
text与keyword是不同的,text会被分析器分析,拆解-组合成多个字或词;keyword不会被分析器分析,仅仅当做一个字符串存储。 - 数字类型:long,integer,short,byte,double,float
- 日期类型:date
- bool类型:boolean
- binary类型:binary (不会被检索)
- 复杂类型:object,nested
- geo类型(地理位置):geo-point,geo-shape
- 专业类型:ip,competion(搜索建议)
什么是object、nested类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# company 是object类型 # company 是{} "company":{ "name":"百度", "company_addr":"北京市软件园" }, # employee 是nested类型 # employee 是[],里面有多个{} "employee":[ { "name":"张三", "age":"18" }, { "name":"李四", "age":"19" }, ] |
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# 创建索引 # type需要在"mappings"下定义 # 对type的字段指定类型,需要在"properties"下操作 # 每个字段使用"type"来指定类型 PUT lagou { "mappings":{ "job":{ "properties": { "title":{ "type":"text" }, "salary_min":{ "type":"integer" }, "city":{ "type":"keyword" }, "company":{ "properties": { "name":{ "type":"text" }, "company_addr":{ "type":"text" }, "employee":{ "type":"integer" } } }, "publish_date":{ "type": "date", "format": "yyyy-MM-dd" }, "comments":{ "type": "integer" } } } } } |
注意:类型一旦创建成功,就不能再修改。
放入数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#放入数据 PUT lagou/job/1 { "title":"python分布式爬虫开发", "salary_min":15000, "city":"北京", "company":{ "name":"百度", "company_addr":"北京市软件园", "employee":50 }, "publish_date":"2017-4-18", "comments":15 } |
支持属性
- //是否单独设置此字段的是否存储而从_source字段中分离,默认是false,只能搜索,不能获取值
"store": false
- //分词,设置false,字段将不会被索引(即不创建倒排索引)
"index": true
- //指定分词器,默认分词器为standard analyzer
"analyzer": "ik"
- //字段级别的分数加权,默认值是1.0
"boost": 1.23
- //对not_analyzed字段,默认都是开启,分词字段不能使用,对排序和聚合能提升较大性能,节约内存
"doc_value": false
- //针对分词字段,参与排序或聚合时能提高性能,不分词字段统一建议使用doc_value
"fielddata": {"format": "disabled"}
- //可以对一个字段提供多种索引模式,同一个字段的值,一个分词,一个不分词
"fields": {"raw": {"type": "string", "index": "not_analyzed"}}
- //超过100个字符的文本,将会被忽略,不被索引
“ignore_above”: 100 - //设置是否此字段包含在_all字段中,默认时true,除非index设置成no
"include_in_all": true
- //4个可选参数docs(索引文档号),freqs(文档号+词频),positions(文档号+词频+位置,通常用来距离查询),offsets(文档号+词频+位置+偏移量,通常被使用在高亮字段)分词字段默认时positions,其他默认时docs
"index_options": "docs"
- //分词字段默认配置,不分词字段:默认{“enable”: false},存储长度因子和索引时boost,建议对需要参加评分字段使用,会额外增加内存消耗
"norms": {"enable": true, "loading": "lazy"}
- //设置一些缺失字段的初始化,只有string可以使用,分词字段的null值也会被分词
"null_value": "NULL"
- //影响距离查询或近似查询,可以设置在多值字段的数据上或分词字段上,查询时可以指定slop间隔,默认值时100
"position_increament_gap": 0
- //设置搜索时的分词器,默认跟analyzer是一致的,比如index时用standard+ngram,搜索时用standard用来完成自动提示功能
"search_analyzer": "ik"
- //默认时TF/IDF算法,指定一个字段评分策略,仅仅对字符串型和分词类型有效
"similarity": "BM25"
- //默认不存储向量信息,支持参数yes(term存储),with_positions(term+位置),with_offsets(term+偏移量),with_positions_offsets(term+位置+偏移量)对快速高亮fast vector highlighter能提升性能,但开启又会加大索引体积,不适合大数据量用
"trem_vector": "no"
ik_max_word
:尽可能多的划词。ik_smart
:中规中矩地划词。示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# 创建索引并添加映射属性 PUT lagou { "mappings":{ "job":{ "properties": { "title":{ "store": true, "type":"text", "analyzer": "ik_max_word" }, "company_name":{ "store": true, "type":"keyword" }, "desc":{ "type": "text" }, "comments":{ "type": "integer" }, "add_time":{ "type": "date", "format": "yyyy-MM-dd" } } } } } |
更多属性,参考官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/6.1/mapping-params.html。
查询
查询的分类:
- 基本查询:使用elasticsearch内置查询条件进行查询
- 组合查询:把多个查询组合在一起进行复合查询
- 过滤:查询同时,通过filter条件在不影响打分的情况下筛选数据
基本查询
准备索引:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# 创建索引并添加映射 PUT lagou { "mappings":{ "job":{ "properties": { "title":{ "store": true, "type":"text", "analyzer": "ik_max_word" }, "company_name":{ "store": true, "type":"keyword" }, "desc":{ "type": "text" }, "comments":{ "type": "integer" }, "add_time":{ "type": "date", "format": "yyyy-MM-dd" } } } } } |
放入数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
POST lagou/job/ { "title":"python django 开发工程师", "company_name":"美团科技有限公司", "desc":"对django的概念熟悉,熟悉python基础知识", "comments":20, "add_time":"2017-4-1" } POST lagou/job/ { "title":"python scrapy redis分布式爬虫基本", "company_name":"百度科技有限公司", "desc":"对scrapy的概念熟悉,熟悉Redis基本操作", "comments":5, "add_time":"2017-4-15" } POST lagou/job/ { "title":"elasticsearch打造搜索引擎", "company_name":"阿里巴巴科技有限公司", "desc":"熟悉数据结构算法,熟悉python基础开发", "comments":15, "add_time":"2017-6-20" } POST lagou/job/ { "title":"python打造推荐引擎系统", "company_name":"阿里巴巴科技有限公司", "desc":"熟悉推荐引擎的原理以及算法,掌握C语言", "comments":60, "add_time":"2017-4-1" } |
match查询
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# match查询 # "title"是被查询的字段,不是固定值 #(1)title的值会被分词(有大小写会被处理成同一个) #(2)title字段匹配任意一个,即匹配成功 # 如果title字段是keyword类型,需要完全一致才能匹配 GET lagou/job/_search { "query": { "match": { "title": "python爬虫" } } } |
term查询
1 2 3 4 5 6 7 8 9 10 11 12 |
# term查询 # "title"是被查询的字段,不是固定值 #(1)title的值不会被分词 # 如果title字段是keyword类型,需要完全一致才能匹配 GET lagou/job/_search { "query": { "term": { "title": "python爬虫" } } } |
terms查询
1 2 3 4 5 6 7 8 9 10 11 |
# terms查询 # "title"是被查询的字段,不是固定值 # title的值有多个,匹配任意一个即可 GET lagou/job/_search { "query": { "terms": { "title": ["工程师","django","系统"] } } } |
控制查询的返回数量
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#控制查询的返回数量 # "from": 0,从第0个开始 # "size": 2,只取2个 GET lagou/job/_search { "query": { "match": { "title": "python" } }, "from": 0, "size": 2 } |
match_all查询
1 2 3 4 5 6 7 8 |
#match_all查询 # 查询所有 GET lagou/job/_search { "query": { "match_all": {} } } |
match_phrase 短语查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#match_phrase 短语查询 # "query": "python系统",会分词, # 且同时满足(既要有"python",又要有"系统")即可匹配成功 # "slop":6 "python"与"系统"之间的最小字符距离 GET lagou/job/_search { "query": { "match_phrase": { "title": { "query": "python系统", "slop":6 } } } } |
multi_match查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#multi_match查询 #比如可以指定多个字段 #比如查询title和desc这两个字段里面包含python的关键词文档 # title^3表示title的三倍权重 GET lagou/job/_search { "query": { "multi_match": { "title": { "query": "python", "fields":["title^3","desc"] } } } } |
指定返回字段
1 2 3 4 5 6 7 8 9 10 11 |
#指定返回字段 # 只对store为true的字段生效 GET lagou/job/_search { "stored_fields": ["title","company_name"], "query": { "match": { "title": "python" } } } |
通过sort把结果排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#通过sort把结果排序 GET lagou/job/_search { "query": { "match_all": {} }, "sort": [ { "comments": { "order": "desc" } } ] } |
range 查询范围
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#range 查询范围 #"gte": 10,大于等于10 #"lte": 20,小于等于20 #"boost": 2.0 权重为2.0 GET lagou/job/_search { "query": { "range": { "comments": { "gte": 10, "lte": 20, "boost": 2.0 } } } } GET lagou/job/_search { "query": { "range": { "add_time": { "gte": "2017-04-01", "lte": "now" } } } } |
wildcard 模糊查询
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#wildcard 模糊查询 # "value": "pyth*n",*代替任何字符 GET lagou/job/_search { "query": { "wildcard": { "title": { "value": "pyth*n", "boost": 2.0 } } } } |
组合查询(bool查询)
老版本的filtered已经被bool替换,用bool包括must、should、must_not、filter来完成。
格式如下:
1 2 3 4 5 6 7 |
# 个数多用[],只有一个用{} bool:{ "filter":[],#字段的过滤,不参与打分 "must":[],#里面的所有查询都必须同时满足 "should":[],#里面的所有查询满足一个或多个 "must_not":[]#里面的所有查询全都不满足 } |
建立测试数据:
1 2 3 4 5 6 7 8 9 10 |
#建立测试数据 POST lagou/testjob/_bulk {"index":{"_id":1}} {"salary":10,"title":"Python"} {"index":{"_id":2}} {"salary":20,"title":"Scrapy"} {"index":{"_id":3}} {"salary":30,"title":"Django"} {"index":{"_id":4}} {"salary":30,"title":"Elasticsearch"} |
简单过滤查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#最简单的filter查询 #select * from testjob where salary=20 #filtered 薪资为20K的工作 GET lagou/testjob/_search { "query": { "bool": { "must": { "match_all":{} }, "filter": { "term": { "salary": 20 } } } } } |
也可以指定多个值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#也可以指定多个值 GET lagou/testjob/_search { "query": { "bool": { "must": { "match_all":{} }, "filter": { "term": { "salary": [10,20] } } } } } |
查看分析器解析的结果
查看分析器解析的结果,在 “text”里写入文本,就会使用指定的分析器对文本进行分词,并把结果输出。
1 2 3 4 5 6 |
#查看分析器解析的结果 GET /_analyze { "analyzer": "ik_max_word", "text": "python" } |
bool过滤查询,可以做组合过滤查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#select * from testjob where (salary=20 or title=Python) and (salary != 30) #查询薪资等于20k或者工作为python的工作,排除价格为30k的 GET lagou/testjob/_search { "query": { "bool": { "should": [ {"term": {"salary": 20}}, {"term": {"title": "python"}} ], "must_not": { "term":{"price":30} } } } } |
嵌套查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#嵌套查询 #select * from testjob where title="python" or (title="elasticsearch" and salary=30) GET lagou/testjob/_search { "query": { "bool": { "should": [ {"term": {"salary": 20}}, {"bool": { "must": [ {"term": {"title": "elasticsearch"}}, {"term": {"salary": 30}} ] }} ] } } } |
过滤空和非空
建立测试数据:
1 2 3 4 5 6 7 8 9 10 11 12 |
#建立测试数据 POST lagou/testjob2/_bulk {"index":{"_id":1}} {"tags":["search"]} {"index":{"_id":2}} {"tags":["search","python"]} {"index":{"_id":3}} {"tags":["some data"]} {"index":{"_id":4}} {"tags":null} {"index":{"_id":5}} {"tags":["search",null]} |
处理null空值的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#处理null空值的方法 #select tags from testjob2 where tags is not null GET lagou/testjob2/_search { "query": { "bool": { "filter": { "exists": { "field": "tags" } } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 |
GET lagou/testjob2/_search { "query": { "bool": { "must_not": { "exists": { "field": "tags" } } } } } |