使用elasticsearch进行搜索 1
- elasticsearch 查询
search API就是对存储在elastic search(以下简称es)中数据进行查询的相关API,可以类比MySQL中的select语句。es中的search主要分为URI search 和query dsl语法为主;
es的Query DSL以_search为endpoint,主要分为字段类查询和复合查询()。
字段类查询: 只针对某一个字段进行查询,如 match、term等; 复合查询: 可以进行一个或多个字段的查询,如bool查询等;
字段类查询主要包括两类:单词匹配和全文匹配
- 单词匹配(Term Level Query)
不对查询语句进行分词处理,直接匹配该字段的倒排索引;
- 全文匹配(Full Text Query)
对指定的text类型的字段进行全文检索,会先对查询语句进行分词处理。例如你输入的查询文本是"我在马路边",es在分词器的作用下就会分词为"我"、"在"、"马路"这么几个单词,然后再去匹配。
字段类查询
1. 全文匹配 包括match、match_phrase、query_string、simple_query_string查询语句;
- match query 是最基本的基于全文检索的字段类查询语法
GET /_search
{
"query": {
"match": {
"message": "this is a test"
}
}
}
那么这里经过分词后的this、is、a、test各个单词之间就是默认为"或"的匹配关系,可以通过operator关键字来显式设置各个单词间的匹配关系,如下:
GET /_search
{
"query": {
"match": {
"message": "this is a test",
"operator": "and"
}
}
}
也可以通过minimum_should_match参数来设置控制需要匹配的单词数,比如你的文档里username存的内容是"this is a java enginer",那么通过下面的查询语句可以控制查询文本最少要匹配到"java"、"enginer":
GET /_search
{
"query": {
"match" : {
"username": {
"query": "java enginer",
"minimum_should_match":2
}
}
}
}
- match_phrase query
match_phrase 也是对字段进行检索,和match_query是有顺序需求的,而match是无序的。
可以通过slop参数来控制单词之间的允许间隔:
GET /_search
{
"query":{
"match_phrase": {
"username": {
"query": "java php enginer",
"slop": "2"
}
}
}
}
- query_string query
GET /_search
{
"query": {
"query_string": {
"default_field": "content",
"query": "this and that or thus"
}
}
}
多字段匹配
GET /_search
{
"query": {
"query_string": {
"fields": ["content", "name"],
"query": "this and that"
}
}
}
- simple_query_string
语法与query_string类似,但是不支持AND、OR、NOT,分别需要用"+"、"|"、"-"号代替。
2. 单词匹配
包括term terms range查询语句:
- term query
term查询语句不会对查询语句进行分词处理,直接拿查询输入的文本去检索,如下是官方文档测试案例,非常清晰:
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"full_text": {
"type": "text"
},
"exact_value": {
"type": "keyword"
}
}
}
}
}
PUT my_index/_doc/1 # 创建一个ID
{
"full_text": "Quick Foxes!",
"exact_value": "Quick Foxes!"
}
GET my_index/_search #查看 可以匹配到 类型为keyword的field
{
"query": {
"term" : {
"exact_value": "Quick Foxes!"
}
}
}
# 不能匹配到结果,因full_text字段类型为text,会 #对原始文本分词为quick 、foxes
{
"query": {
"term" : {
"full_text": "Quick Foxes!"
}
}
}
# 可以匹配到结果
{
"query": {
"term" : {
"full_text": "Foxes!"
}
}
}
# 使用match 会对quick foxes 进行查询时分词
{
"query": {
"match" : {
"full_text": "Quick Foxes!"
}
}
}
- terms query
terms和term的查询语法基本类似,但terms支持的查询文本可以多个:
{
"query": {
"terms": {
"username": ["java", "elstic"]
}
}
}
此外,terms还支持文档元数据信息的几个字段值查询:
- index
- type
- id
- path
- routing
GET /index1/_search
{
"query":{
"terms":{
"user": {
"index": "users",
"type": "_doc",
"id": "2",
"path": "followers"
}
}
}
}
- range query
范围查询主要用于date或number类型的字段查询中,和term、terms查询一样,不进行查询时分词:
GET _search
{
"query": {
"range": {
"age": 10,
"lte": 20,
"boost": 2.0
}
}
}
其中gte表示大于等于,lte表示小于等于,gt表示大于,lt表示小于,boost表示对此次query进行相关性算分权重,默认是1.0
POST my_test_index1/userinfo/
{
"name": "simons",
"age": 24,
"birth": "2020-10-10"
}
GET my_test_index1/userinfo/_search
{
"query": {
"range": {
"brith": {
"gt": "now-3y"
}
}
}
}
在range范围查询中,es提供了一种更加简单的日期计算,
now表示当前时间,
y:年,
M:月,
d:天,
H:时,
m:分,
s:秒,
所以now-3y就是三年之前的时间。
复合查询
复合查询就是指可以对多个字段过滤筛选,类比mysql的where多条件查询,es的复合查询包括 Constant Score Query、Bool Query、Dis Max Query、Function Score Query、Boosting Query,这里详细说一说用的比较多的Bool Query。
Bool Query是由一个或多个bool子句构成的,包括:
Bool查询的基本语法如下:
GET my_test_index2/userinfo/_search
{
"query": {
"bool": {
"must":[
"match": {
"name": "simons"
}
],
"must not": [
{
"term": {
"address": {
"value": "japan"
}
}
}
],
"should": [
{
"term": {
"age":24
}
}
],
"filter":{
"term":{
"name": "simons"
}
}
}
}
}
1、must、must_not、should支持数组,同时filter的查询语句,es会对其进行智能缓存,因此执行效率较高,在不需要算分的查询语句中,可以考虑使用filter替代普通的query语句;
2、查询语句同时包含must和should时,可以不满足should的条件,因为must条件优先级高于should,但是如果也满足should的条件,则会提高相关性算分;
3、可以使用minimum_should_match参数来控制应当满足条件的个数或百分比;
4、must、must_not语句里面如果包含多个条件,则各个条件间是且的关系,而should的多个条件是或的关系。
参考文档: Elastic Search之Search API(Query DSL)、字段类查询、复合查询
- filter 过滤器
尽管我们之前已经涉及了查询DSL,然而实际上存在两种DSL:查询DSL(query DSL)和过滤DSL(filter DSL)。 过滤器(filter)通常用于过滤文档的范围,比如某个字段是否属于某个类型,或者是属于哪个时间区间
- 创建日期是否在2014-2015年间?
- status字段是否为success?
查询器(query)的使用方法像极了filter,但query更倾向于更准确的查找。
-
与full text search的匹配度最高
-
正则匹配
-
包含run单词,如果包含这些单词:runs、running、jog、sprint,也被视为包含run单词
-
包含quick、brown、fox。这些词越接近,这份文档的相关性就越高 查询器会计算出每份文档对于某次查询有多相关(relevant),然后分配文档一个相关性分数:_score。而这个分数会被用来对匹配了的文档进行相关性排序。相关性概念十分适合全文搜索(full-text search),这个很难能给出完整、“正确”答案的领域。
query filter在性能上对比:filter是不计算相关性的,同时可以cache。因此,filter速度要快于query。
如果你想同时使用query和filter查询的话,需要使用 {query:{filtered:{}}} 来包含这两个查询语法。他们的好处是,借助于filter的速度可以快速过滤出文档,然后再由query根据条件来匹配。
"query": {
"filtered": {
"query": { "match": { "email": "business opportunity" }},
"filter": { "term": { "folder": "inbox" }}
}
}
}
{ "size":0,
"query": {
"filtered": {
"query": {
"bool": {
"should": [],
"must_not": [
],
"must": [
{
"term": {
"channel_name":"微信自媒体微信"
}
}
]
}
}
},
"filter":{
"range": {
"idate": {
"gte": "2015-09-01T00:00:00",
"lte": "2015-09-10T00:00:00"
}
}
}
}
}
python 应用示例:
过滤近两天生成的目标
q_data2 = {"query": {"filtered": {"filter": {"range": {"created_at": {"lt": "","gt": ""}}}}},
"sort": {"created_at": {"order": ""}}}
q_data2["query"]["filtered"]["filter"]["range"]["created_at"]["lt"] = "now"
q_data2["query"]["filtered"]["filter"]["range"]["created_at"]["gt"] = "now-1d"
q_data2["sort"]["created_at"]["order"] = "desc"
q_data2["size"] = end_num
q_data2["from"] = start_num
按字段不分词匹配
# ids = [id1, id2 ...idn]
{'query': {'terms': {'alerts_id': ids}}}
query 搜索框 默认搜索所有字段
'query': {
'multi_match': {
'query': u '安全',
'fields': '_all'
}
}
方法:
import json
import urllib2
import base64
def query(options, indices, q_data):
base64string = base64.b64encode(
'%s:%s' % (options.es_user, options.es_pawd))
req = urllib2.Request(options.elasticsearch_api + indices + "/_search", json.dumps(q_data))
req.add_header("Authorization", "Basic %s" % base64string)
response = urllib2.urlopen(req).read()
ret = json.loads(response)['hits']
return ret