elasticsearch——入门
elasticsearch 学习整理
索引和值:增删查改
In [2]: from elasticsearch import Elasticsearch
    
In [8]: es = Elasticsearch([{'host':'192.168.3.215','port':9215}])
# 创建索引
In [11]: res = es.indices.create(index='wl_test')
In [12]: print(res)
{'acknowledged': True, 'shards_acknowledged': True, 'index': 'wl_test'}
# 重复创建索引,报错 400
RequestError: RequestError(400, 'resource_already_exists_exception', 'index [wl_test/CEwdWyvfSzO4oQVpafZpsg] already exists')
# ignore 参数,忽略 400 不会报错
In [15]: es.indices.create(index='wl_test',ignore=[400])
Out[15]:
{'error': {'root_cause': [{'type': 'resource_already_exists_exception',
    'reason': 'index [wl_test/CEwdWyvfSzO4oQVpafZpsg] already exists',
    'index_uuid': 'CEwdWyvfSzO4oQVpafZpsg',
    'index': 'wl_test'}],
  'type': 'resource_already_exists_exception',
  'reason': 'index [wl_test/CEwdWyvfSzO4oQVpafZpsg] already exists',
  'index_uuid': 'CEwdWyvfSzO4oQVpafZpsg',
  'index': 'wl_test'},
 'status': 400}
# 删除索引
In [16]: es.indices.delete(index='wl_test')
Out[16]: {'acknowledged': True}
    
# 重复删除索引,报错 404
NotFoundError: NotFoundError(404, 'index_not_found_exception', 'no such index [wl_test]', wl_test, index_or_alias)
    
# ignore 参数,忽略 404 不会报错
In [18]: es.indices.delete(index='wl_test',ignore=[404])
Out[18]:
{'error': {'root_cause': [{'type': 'index_not_found_exception',
    'reason': 'no such index [wl_test]',
    'index_uuid': '_na_',
    'resource.type': 'index_or_alias',
    'resource.id': 'wl_test',
    'index': 'wl_test'}],
  'type': 'index_not_found_exception',
  'reason': 'no such index [wl_test]',
  'index_uuid': '_na_',
  'resource.type': 'index_or_alias',
  'resource.id': 'wl_test',
  'index': 'wl_test'},
 'status': 404}
# 我们需要善用 ignore 参数,把一些意外情况排除,这样可以保证程序的正常执行而不会中断。
# 插入数据
IIn [20]: data = {'title':'测试','q':"what's your name?"}
In [21]: res = es.create(index= 'wl_test',doc_type='data',id = 1,body=data)
DeprecationWarning: The 'body' parameter is deprecated for the 'create' API and will be removed in a future version. Instead use the 'document' parameter. See https://github.com/elastic/elasticsearch-py/issues/1698 for more information
d:\python36\lib\site-packages\elasticsearch\connection\base.py:209: ElasticsearchWarning: [types removal] Specifying types in document index requests is deprecated, use the typeless endpoints instead (/{index}/_doc/{id}, /{index}/_doc, or /{index}/_create/{id}).
  warnings.warn(message, category=ElasticsearchWarning)
In [25]: res = es.create(index= 'wl_test',doc_type='data',id = 2,document=data)
ElasticsearchWarning: [types removal] Specifying types in document index requests is deprecated, use the typeless endpoints instead (/{index}/_doc/{id}, /{index}/_doc, or /{index}/_create/{id}).warnings.warn(message, category=ElasticsearchWarning)
In [26]: res
Out[26]:
{'_index': 'wl_test',
 '_type': 'data',
 '_id': '2',
 '_version': 1,
 'result': 'created',
 '_shards': {'total': 2, 'successful': 2, 'failed': 0},
 '_seq_no': 1,
 '_primary_term': 1}
# create 方法插入数据,创建文档必须有 id
In [27]: res = es.create(index= 'wl_test',doc_type='data',document=data)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
 in 
----> 1 res = es.create(index= 'wl_test',doc_type='data',document=data)
d:\python36\lib\site-packages\elasticsearch\client\utils.py in _wrapped(*args, **kwargs)
    299                 if p in kwargs:
    300                     params[p] = kwargs.pop(p)
--> 301             return func(*args, params=params, headers=headers, **kwargs)
    302
    303         return _wrapped
TypeError: create() missing 1 required positional argument: 'id'
        
# index 方法,插入数据,不用指定 id,随机id;create 方法 是对 index 方法的封装。
In [28]: es.index(index='wl_test',doc_type='data',body= data)
Out[28]:
{'_index': 'wl_test',
 '_type': 'data',
 '_id': 'JouMRX0Bd_s0QCOkwdWF',
 '_version': 1,
 'result': 'created',
 '_shards': {'total': 2, 'successful': 2, 'failed': 0},
 '_seq_no': 2,
 '_primary_term': 1}
# update 更新数据
# 注意 body 参数,我们需要添加 doc 或者 script 变量来指定修改的内容
In [45]: data={'doc':{'title':'aaa','q':'bbb'}}
In [46]: es.update(index='wl_test',doc_type='data',body=data,id=1)
# _version 字段 版本号,每次更新都 +1
Out[46]:
{'_index': 'wl_test',
 '_type': 'data',
 '_id': '1',
 '_version': 2,
 'result': 'updated',
 '_shards': {'total': 2, 'successful': 2, 'failed': 0},
 '_seq_no': 3,
 '_primary_term': 1}
# updat 不存在的 id
NotFoundError: NotFoundError(404, 'document_missing_exception', '[data][10]: document missing')
    
# index 更新,如果 id 存在则创建
In [48]: es.index(index='wl_test',doc_type='data',body=data,id = 10)
Out[48]:
{'_index': 'wl_test',
 '_type': 'data',
 '_id': '10',
 '_version': 1,
 'result': 'created',
 '_shards': {'total': 2, 'successful': 2, 'failed': 0},
 '_seq_no': 4,
 '_primary_term': 1}
In [49]: es.index(index='wl_test',doc_type='data',body=data,id = 10)
Out[49]:
{'_index': 'wl_test',
 '_type': 'data',
 '_id': '10',
 '_version': 2,
 'result': 'updated',
 '_shards': {'total': 2, 'successful': 2, 'failed': 0},
 '_seq_no': 5,
 '_primary_term': 1}
# delete 删除数据, result 字段为 deleted,代表删除成功,_version 变成了 3,又增加了 1。
In [50]: es.delete(index='wl_test',doc_type='data',id=10)
Out[50]:
{'_index': 'wl_test',
 '_type': 'data',
 '_id': '10',
 '_version': 3,
 'result': 'deleted',
 '_shards': {'total': 2, 'successful': 2, 'failed': 0},
 '_seq_no': 6,
 '_primary_term': 1}
# 重新创建,_version +1
In [51]: es.index(index='wl_test',doc_type='data',id=10,document=data)
Out[51]:
{'_index': 'wl_test',
 '_type': 'data',
 '_id': '10',
 '_version': 4,
 'result': 'created',
 '_shards': {'total': 2, 'successful': 2, 'failed': 0},
 '_seq_no': 7,
 '_primary_term': 1}
# 查询数据:对于中文需要安装中文分词插件
#  elasticsearch-analysis-ik,GitHub 链接为:https://github.com/medcl/elasticsearch-analysis-ik,这里我们使用 Elasticsearch 的另一个命令行工具 elasticsearch-plugin 来安装,这里安装的版本是 6.2.4,请确保和 Elasticsearch 的版本对应起来,命令如下:
elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.3.0/elasticsearch-analysis-ik-7.3.0.zip
# 查看是否中文分词器安装成功
[root@b4de731914a2 elasticsearch]# /usr/share/elasticsearch/bin/elasticsearch-plugin list
analysis-ik
# 安装之后重新启动 Elasticsearch 就可以了,它会自动加载安装好的插件。
# 首先我们新建一个索引并指定需要分词的字段
In [73]: mapping
Out[73]:
{'properties': {'title': {'type': 'text',
   'analyzer': 'ik_max_word',
   'search_analyzer': 'ik_max_word'}}}
es.indices.create(index='news', ignore=400)
# 更新 mapping
result = es.indices.put_mapping(index='news', doc_type='politics', body=mapping)
# 插入数据
datas = [
    {
        'title': '美国留给伊拉克的是个烂摊子吗',
        'url': 'http://view.news.qq.com/zt2011/usa_iraq/index.htm',
        'date': '2011-12-16'
    },
    {
        'title': '公安部:各地校车将享最高路权',
        'url': 'http://www.chinanews.com/gn/2011/12-16/3536077.shtml',
        'date': '2011-12-16'
    },
    {
        'title': '中韩渔警冲突调查:韩警平均每天扣1艘中国渔船',
        'url': 'https://news.qq.com/a/20111216/001044.htm',
        'date': '2011-12-17'
    },
    {
        'title': '中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首',
        'url': 'http://news.ifeng.com/world/detail_2011_12/16/11372558_0.shtml',
        'date': '2011-12-18'
    }
]
 
for data in datas:
    es.index(index='news', doc_type='politics', body=data)
  查询:
In [74]: es.search(index='wl_test',doc_type='data')
d:\python36\lib\site-packages\elasticsearch\connection\base.py:209: ElasticsearchWarning: [types removal] Specifying types in search requests is deprecated.
  warnings.warn(message, category=ElasticsearchWarning)
Out[74]:
{'took': 54,
 'timed_out': False,
 '_shards': {'total': 1, 'successful': 1, 'skipped': 0, 'failed': 0},
 'hits': {'total': {'value': 4, 'relation': 'eq'},
  'max_score': 1.0,
  'hits': [{'_index': 'wl_test',
    '_type': 'data',
    '_id': 'wVk5Rn0BM5UnHl8RH9ZL',
    '_score': 1.0,
    '_source': {'title': '美国留给伊拉克的是个烂摊子吗',
     'url': 'http://view.news.qq.com/zt2011/usa_iraq/index.htm',
     'date': '2011-12-16'}},
   {'_index': 'wl_test',
    '_type': 'data',
    '_id': 'wlk5Rn0BM5UnHl8RINYy',
    '_score': 1.0,
    '_source': {'title': '公安部:各地校车将享最高路权',
     'url': 'http://www.chinanews.com/gn/2011/12-16/3536077.shtml',
     'date': '2011-12-16'}},
   {'_index': 'wl_test',
    '_type': 'data',
    '_id': 'w1k5Rn0BM5UnHl8RINZK',
    '_score': 1.0,
    '_source': {'title': '中韩渔警冲突调查:韩警平均每天扣1艘中国渔船',
     'url': 'https://news.qq.com/a/20111216/001044.htm',
     'date': '2011-12-17'}},
   {'_index': 'wl_test',
    '_type': 'data',
    '_id': 'xFk5Rn0BM5UnHl8RINZe',
    '_score': 1.0,
    '_source': {'title': '中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首',
     'url': 'http://news.ifeng.com/world/detail_2011_12/16/11372558_0.shtml',
     'date': '2011-12-18'}}]}}
In [75]: es.search(index='wl_test')
Out[75]:
{'took': 7,
 'timed_out': False,
 '_shards': {'total': 1, 'successful': 1, 'skipped': 0, 'failed': 0},
 'hits': {'total': {'value': 4, 'relation': 'eq'},  # 结果数量
  'max_score': 1.0,  # 最大匹配分数
  'hits': [{'_index': 'wl_test',
    '_type': 'data',
    '_id': 'wVk5Rn0BM5UnHl8RH9ZL',
    '_score': 1.0,
    '_source': {'title': '美国留给伊拉克的是个烂摊子吗',
     'url': 'http://view.news.qq.com/zt2011/usa_iraq/index.htm',
     'date': '2011-12-16'}},
   {'_index': 'wl_test',
    '_type': 'data',
    '_id': 'wlk5Rn0BM5UnHl8RINYy',
    '_score': 1.0,
    '_source': {'title': '公安部:各地校车将享最高路权',
     'url': 'http://www.chinanews.com/gn/2011/12-16/3536077.shtml',
     'date': '2011-12-16'}},
   {'_index': 'wl_test',
    '_type': 'data',
    '_id': 'w1k5Rn0BM5UnHl8RINZK',
    '_score': 1.0,
    '_source': {'title': '中韩渔警冲突调查:韩警平均每天扣1艘中国渔船',
     'url': 'https://news.qq.com/a/20111216/001044.htm',
     'date': '2011-12-17'}},
   {'_index': 'wl_test',
    '_type': 'data',
    '_id': 'xFk5Rn0BM5UnHl8RINZe',
    '_score': 1.0,
    '_source': {'title': '中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首',
     'url': 'http://news.ifeng.com/world/detail_2011_12/16/11372558_0.shtml',
     'date': '2011-12-18'}}]}}
In [76]: dsl = {  # 通过 DSL 查询
    ...: 'query':{
    ...: 'match':{
    ...: 'title':'中国 领事馆'
    ...: }
    ...: }
    ...: }
    
In [77]: es.search(index='wl_test',doc_type='data',body=dsl)
D:\python36\Scripts\ipython:1: DeprecationWarning: The 'body' parameter is deprecated for the 'search' API and will be removed in a future version. Instead use API parameters directly. See https://github.com/elastic/elasticsearch-py/issues/1698 for more information
d:\python36\lib\site-packages\elasticsearch\connection\base.py:209: ElasticsearchWarning: [types removal] Specifying types in search requests is deprecated.
  warnings.warn(message, category=ElasticsearchWarning)
Out[77]:
{'took': 30,
 'timed_out': False,
 '_shards': {'total': 1, 'successful': 1, 'skipped': 0, 'failed': 0},
 'hits': {'total': {'value': 2, 'relation': 'eq'},
  'max_score': 3.9923213,
  'hits': [{'_index': 'wl_test',
    '_type': 'data',
    '_id': 'xFk5Rn0BM5UnHl8RINZe',
    '_score': 3.9923213,
    '_source': {'title': '中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首',
     'url': 'http://news.ifeng.com/world/detail_2011_12/16/11372558_0.shtml',
     'date': '2011-12-18'}},
   {'_index': 'wl_test',
    '_type': 'data',
    '_id': 'w1k5Rn0BM5UnHl8RINZK',
    '_score': 0.642793,
    '_source': {'title': '中韩渔警冲突调查:韩警平均每天扣1艘中国渔船',
     'url': 'https://news.qq.com/a/20111216/001044.htm',
     'date': '2011-12-17'}}]}}
# 检索时会对对应的字段全文检索,结果还会按照检索关键词的相关性进行排序,这就是一个基本的搜索引擎雏形。
mapping 类型
属性名字 说明
text 用于全文索引,该类型的字段将通过分词器进行分词,最终用于构建索引
keyword 不分词,只能搜索该字段的完整的值,只用于 filtering
long	有符号64-bit integer:-2^63 ~ 2^63 - 1
integer	有符号32-bit integer,-2^31 ~ 2^31 - 1
short	有符号16-bit integer,-32768 ~ 32767
byte	 有符号8-bit integer,-128 ~ 127
double	64-bit IEEE 754 浮点数
float	32-bit IEEE 754 浮点数
half_float	16-bit IEEE 754 浮点数
boolean	true,false
date	https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-date-format.html
binary  该类型的字段把值当做经过 base64 编码的字符串,默认不存储,且不可搜索
字符串类型
在 ES 7.x 有两种字符串类型:text 和 keyword,在 ES 5.x 之后 string 类型已经不再支持了。
text :类型适用于需要被全文检索的字段,例如新闻正文、邮件内容等比较长的文字,text 类型会被 Lucene 分词器(Analyzer)处理为一个个词项,并使用 Lucene 倒排索引存储,text 字段不能被用于排序,如果需要使用该类型的字段只需要在定义映射时指定 JSON 中对应字段的 type 为 text。
keyword:不会被分词,适合简短、结构化字符串,例如主机名、姓名、商品名称等,可以用于过滤、排序、聚合检索,也可以用于精确查询。
各种查询:
# 查询所有
body = {
    "query":{
        "match_all":{}
    }
}
# 等于查询
# term查询:查询 preview 字段里有某个关键词的文档
# terms 查询:查询某个字段里有多个关键词的文档
# term: 查询 xx = “xx”
body = {
    "query":{
        "term":{
            "name":"python"
        }
    }
}
# terms: 查询 xx = “xx” 或 xx = “yy”
body = {
    "query":{
        "terms":{
            "name":[
                "ios","android"
            ]
        }
    }
}
# 包含查询
# match 查询可以接受文字,数字日期等数据类型
# match 和term的区别是,match 查询的时候,elasticsearch会根据你给定的字段提供合适的分析器,而term查询时不会有分析器分析的过程
# match: 匹配name包含"python"关键字的数据
body = {
    "query":{
        "match":{
            "name":"python"
        }
    }
}
# multi_match: 在name和addr里匹配包含深圳关键字的数据
body = {
    "query":{
        "multi_match":{
            "query":"深圳",
            "fields":["name", "addr"]
        }
    }
}
# 通过match_phrase查询
# 短语查询,slop定义的关键词之间隔多个未知的单词
# 查询elasticsearch,distributed 之间间隔2个单词的文档
{
	"query"{
	"match_phrase":{
		"preview":{
		"query":"Elasticsearch,distributed",
		"slop":2
		}
	}
}
    
# ids 查询id
# 搜索出id为1或2的所有数据
body = {
    "query":{
        "ids":{
            "type":"type_name",
            "values":[
                "1","2"
            ]
        }
    }
}
# 复合查询 bool 查询:bool有3类查询关系,must(都满足),should(其中一个满足),must_not(都不满足)
# 获取name="python"并且age=18的所有数据
body = {
    "query":{
        "bool":{
            "must":[
                {
                    "term":{
                        "name":"python"
                    }
                },
                {
                    "term":{
                        "age":18
                    }
                }
            ]
        }
    }
}
# 切片式查询
# 从第2条数据开始,获取4条数据,索引 从 0 开始
body = {
    "query":{
        "match_all":{}
    },
    "from":2,    # 从第二条数据开始
    "size":4,    # 获取4条数据
}
# 范围查询
# 查询18<=age<=30的所有数据
body = {
    "query":{
        "range":{
            "age":{
                "gte":18,       # >=18
                "lte":30        # <=30
            }
        }
    }
}
# 前缀查询
# 查询前缀为"赵"的所有数据
body = {
    "query":{
        "prefix":{
            "name":"p"
        }
    }
}
# 查询name以id为后缀的所有数据
body = {
    "query":{
        "wildcard":{
            "name":"*id"
        }
    }
}
# 排序
body = {
    "query":{
        "match_all":{}
    }
    "sort":{
        "age":{                 # 根据age字段升序排序
            "order":"asc"       # asc升序,desc降序
        }
    }
}
# 多字段排序,注意顺序!写在前面的优先排序
body = {
    "query":{
        "match_all":{}
    }
    "sort":[{
        "age":{                # 先根据age字段升序排序
            "order":"asc"      # asc升序,desc降序
        }
    },{
        "name":{               # 后根据name字段升序排序
            "order":"asc"      # asc升序,desc降序
        }
    }],
}
# filter_path, 响应过滤
# 只要 _id 数据
In [147]: es.search(index='wl_test',doc_type='data',filter_path=('hits.hits._id'))
d:\python36\lib\site-packages\elasticsearch\connection\base.py:209: ElasticsearchWarning: [types removal] Specifying types in search requests is deprecated.
  warnings.warn(message, category=ElasticsearchWarning)
Out[147]:
{'hits': {'hits': [{'_id': 'wVk5Rn0BM5UnHl8RH9ZL'},
   {'_id': 'wlk5Rn0BM5UnHl8RINYy'},
   {'_id': 'w1k5Rn0BM5UnHl8RINZK'},
   {'_id': 'xFk5Rn0BM5UnHl8RINZe'}]}}
# 多个条件用逗号隔开
In [149]: es.search(index='wl_test',doc_type='data',filter_path=('hits.hits._id','hits.hits._source'))
d:\python36\lib\site-packages\elasticsearch\connection\base.py:209: ElasticsearchWarning: [types removal] Specifying types in search requests is deprecated.
  warnings.warn(message, category=ElasticsearchWarning)
Out[149]:
{'hits': {'hits': [{'_id': 'wVk5Rn0BM5UnHl8RH9ZL',
    '_source': {'title': '美国留给伊拉克的是个烂摊子吗',
     'url': 'http://view.news.qq.com/zt2011/usa_iraq/index.htm',
     'date': '2011-12-16'}},
   {'_id': 'wlk5Rn0BM5UnHl8RINYy',
    '_source': {'title': '公安部:各地校车将享最高路权',
     'url': 'http://www.chinanews.com/gn/2011/12-16/3536077.shtml',
     'date': '2011-12-16'}},
   {'_id': 'w1k5Rn0BM5UnHl8RINZK',
    '_source': {'title': '中韩渔警冲突调查:韩警平均每天扣1艘中国渔船',
     'url': 'https://news.qq.com/a/20111216/001044.htm',
     'date': '2011-12-17'}},
   {'_id': 'xFk5Rn0BM5UnHl8RINZe',
    '_source': {'title': '中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首',
     'url': 'http://news.ifeng.com/world/detail_2011_12/16/11372558_0.shtml',
     'date': '2011-12-18'}}]}}
# count 获取数量
In [150]: es.count(index='wl_test',doc_type='data')
Out[150]:
{'count': 4,
 '_shards': {'total': 1, 'successful': 1, 'skipped': 0, 'failed': 0}}
# 度量类聚合
# 搜索所有数据,并获取age最小的值
body = {
    "query":{
        "match_all":{}
    },
    "aggs":{                        # 聚合查询
        "min_age":{                 # 最小值的key,随便指定
            "min":{                 # 最小
                "field":"age"       # 查询"age"的最小值
            }
        }
    }
}
# 搜索所有数据,并获取age最大的值
body = {
    "query":{
        "match_all":{}
    },
    "aggs":{                        # 聚合查询
        "max_age":{                 # 最大值的key
            "max":{                 # 最大
                "field":"age"       # 查询"age"的最大值
            }
        }
    }
}
# 搜索所有数据,并获取所有age的和,时间类型也可以
body = {
    "query":{
        "match_all":{}
    },
    "aggs":{                        # 聚合查询
        "sum_age":{                 # 和的key
            "sum":{                 # 和
                "field":"age"       # 获取所有age的和
            }
        }
    }
}
# 搜索所有数据,获取所有age的平均值
body = {
    "query":{
        "match_all":{}
    },
    "aggs":{                        # 聚合查询
        "avg_age":{                 # 平均值的key
            "avg":{                 # 平均值
                "field":"age"       # 获取所有age的平均值
            }
        }
    }
}
# from ,size
# from:从“第几条”开始查询
# size:查询多少条
body = {
    "query":{
        "match_all":{}
    },
    "size":"50",
    "from":"0"
}
bool 和 filtered
es 5.0版本更新后,filtered的查询将替换为bool查询。
filtered是比较老的的版本的语法。现在目前已经被bool替代。推荐使用bool。
must 与 filter
must, 返回的文档必须满足must子句的条件,并且参与计算分值
filter, 返回的文档必须满足filter子句的条件。但是跟Must不一样的是,不会计算分值, 并且可以使用缓存
从上面的描述来看,你应该已经知道,如果只看查询的结果,must和filter是一样的。区别是场景不一样。如果结果需要算分就使用must,否则可以考虑使用filter。
为了说明filter查询高效的原因,我们需要引入ES的一个概念 query context和 filter context。
query context
query context关注的是,文档到底有多匹配查询的条件,这个匹配的程度是由相关性分数决定的,分数越高自然就越匹配。所以这种查询除了关注文档是否满足查询条件,还需要额外的计算相关性分数.
filter context
filter context关注的是,文档是否匹配查询条件,结果只有两个,是和否。没有其它额外的计算。它常用的一个场景就是过滤时间范围。
并且filter context会自动被ES缓存结果,效率进一步提高。
对于bool查询,must使用的就是query context,而filter使用的就是filter context。
除了是否计算相关性算分的差别,经常使用的过滤器将被Elasticsearch自动缓存,以提高性能。
filter 查询
{
"query":{
        "bool":{
            "filter":[
                {"term":
                    {"price":40}
                }
            ]
        }
    }
}
filter的两种用法
1 嵌套在bool下
{
  "query": {
    "bool": {
      "must": {
        "term": {
          "term":{"title":"kitchen3"}
        }
      },
      "filter": {
        "term": {
          "price":1000
        }
      }
    }
  }
}
2 在根目录下使用
{
  "query":{
    "term":{"title":"kitchen3"}
  },
  "filter":{
    "term":{"price":1000}
  }
}
位置:bool下
区别:在filter query先执行filter,不计算score,再执行query。
位置:根目录下
区别:根目录中的filter在query后执行。
备注:如果还要在搜索结果中执行aggregation操作,filter query聚合的是filter和query之后的结果,而filter聚合的是query的结果
script 获取值
search,用doc
update,用ctx