ElasticSearch-搜索查询

DELETE school
PUT /school
{
  "mappings": {
    "student": {
      "properties": {
        "age": {
          "type": "long"
        },
        "course": {
          "type": "keyword"
        },
        "name": {
          "type": "text"
        },
        "study_date": {
          "type": "date"
        },
        "mark": {
          "type": "text"
        }
      }
    }
  }
}
POST /school/student/_bulk
{"index":{"_id":"1"}}
{"name":"zhangsan","age":25,"course":"elasticsearch","study_date":"2017-06-15T20:30:50","mark":"today is a good day"}
{"index":{"_id":"2"}}
{"name":"lisi","age":25,"course":"spring","study_date":"2017-06-16T20:30:50","mark":"very good"}
{"index":{"_id":"3"}}
{"name":"wangwu","age":27,"course":"elasticsearch","study_date":"2017-06-17T20:30:50","mark":"sorry day"}
{"index":{"_id":"4"}}
{"name":"zhaoliu","age":28,"course":"elasticsearch","study_date":"2017-06-18T20:30:50","mark":"happy day"}
{"index":{"_id":"5"}}
{"name":"sunqi","age":29,"course":"elasticsearch","study_date":"2017-06-19T20:30:50","mark":"good happy day"}
{"index":{"_id":"6"}}
{"name":"zhouba","age":30,"course":"elasticsearch","study_date":"2017-06-20T20:30:50","mark":"take care day"}
{"index":{"_id":"7"}}
{"name":"wujiu","age":31,"course":"spring elasticsearch","study_date":"2017-06-21T20:30:50","mark":"tab ok"}
{"index":{"_id":"8"}}
{"name":"zhengshi","age":32,"course":"elasticsearch","study_date":"2017-06-21T20:30:50"}
{"index":{"_id":"9"}}
{"name":"aaabbb","age":25,"course":"elasticsearch","study_date":"2017-06-15T20:30:50","mark":"zhangsan today is a good day"}
{"index":{"_id":"10"}}
{"name":"ababab","age":25,"course":"good","study_date":"2017-06-15T20:30:50","mark":"zhangsan say elasticsearch very good"}

URL querystring语法

全文检索:

GET /school/_search?q=zhangsan

单字段全文检索:

GET /school/_search?q=name:zhangsan

条件组合

GET /school/_search?q=+mark:zhangsan -name:aaabbb

单字段精确检索:

GET /school/_search?q=mark:"good day"

多个检索条件的组合:

GET /school/_search?q=name:("zhangsan" OR "lisi") AND NOT course:spring

字段是否存在:

GET /school/_search?q=_exists_:mark
GET /school/_search?q=NOT _exists_:mark

通配符:

用 ? 表示单字母,* 表示任意个字母

GET /school/_search?q=name:zh???san
GET /school/_search?q=name:zh*san

近似搜索:

用 ~ 表示搜索单词可能有一两个字母写的不对,按照相似度返回结果,最多可以模糊2个距离

GET /school/_search?q=name:zhangsnn~

指定近似搜素错误字符

GET /school/_search?q=name:zhangsxx~1

临近搜素

GET /school/_search?q=mark:"today good"~2

范围搜索:对数值和时间,都可以使用范围搜索

[] 表示端点数值包含在范围内,{} 表示端点数值不包含在范围内;
例如:age:>30,date:["now-6h" TO "now"}等。

GET /school/_search?q=age:>30
GET /school/_search?q=age:[28 TO 30]

正则搜索:

(ES 中正则性能不高,尽量不要使用)
保留字符:. ? + * | { } [ ] ( ) " \ # @ & < > ~
转义字符用\,例如:\* \\

.代表一个字符,类似于通配符?

GET /school/_search?q=name:/zh...san/
GET /school/_search?q=name:/zha..s.n/

.*匹配多个,类似于通配符*

GET /school/_search?q=name:/zh.*san/

用*匹配0次或多次

GET /school/_search?q=name:/a*b*/

用?匹配0次或1次

GET /school/_search?q=name:/aaa?bbb?/

下面不能匹配

GET /school/_search?q=name:/aa?bb?/

用{}表示匹配的次数,格式:{至少次数,至多次数}

GET /school/_search?q=name:/a{3}b{3}/
GET /school/_search?q=name:/a{2,4}b{2,4}/

下面不能匹配

GET /school/_search?q=name:/a{4}b{4}/

用()组

GET /school/_search?q=name:/(ab)*/
GET /school/_search?q=name:/(ab){3}/

用|代表或

GET /school/_search?q=name:/(ab){3}|aaabbb/

用[]表示可选字符,用^代表否定

GET /school/_search?q=name:/[ab]*/
GET /school/_search?q=name:/[a-c]*/
GET /school/_search?q=name:/[^ab]*/

Query DSL 完整语法

空查询,默认查询所有的文档

GET school/student/_search
{
  "query": {
    "match_all": {}
  }
}

不匹配任何文档

GET school/student/_search
{
    "query": {
        "match_none": {}
    }
}

match 查询

match查询执行步骤:

  1. 检查字段类型;
  2. 分析查询字符串;
  3. 查找匹配文档;
  4. 为每个文档评分。
GET school/student/_search
{
  "query": {
    "match": {
      "mark": "day"
    }
  }
}

多词match 查询,默认是或关系,有其中一个词即可

GET school/student/_search
{
  "query": {
    "match": {
      "mark": "good day"
    }
  }
}

等同于

GET school/student/_search
{
  "query": {
    "match": {
      "mark": {
        "query":"good day",
        "operator":"or"
      }
    }
  }
}

控制匹配的项目个数

GET school/student/_search
{
  "query": {
    "match": {
      "mark": {
        "query":"good happy day ",
        "minimum_should_match": "2"
      }
    }
  }
}

与关系,必须包含所有词

等同于:GET /school/_search?q=mark:good AND mark:day

GET school/student/_search
{
  "query": {
    "match": {
      "mark": {
        "query":"good day",
        "operator":"and"
      }
    }
  }
}

短语匹配(match_phrase):

等同于GET /school/_search?q=mark:"good day"
查询的结果是必须挨着的短语,默认slop=0

执行步骤:

  1. 分析查询字符串,分解成词项;
  2. 查找匹配文档;
  3. 只保留包含全部词项的文档,并且词项位置也相同;
  4. slop指定词项间隔的范围。
GET school/student/_search
{
  "query": {
    "match_phrase": {
      "mark": "good day"
    }
  }
}

短语匹配,slop指定词项间隔离的范围

GET school/student/_search
{
  "query": {
    "match_phrase": {
      "mark": {
        "query":"good day",
        "slop":1
      }
    }
  }
}

短语前缀匹配查询(match_phrase_prefix)

slop指定词项间隔离的范围,max_expansions最多查到前缀多少个词项停止,默认50,默认在所有分片上,找到匹配到前缀的前50个词。
5.0之后可以使用"profile": true,可以看到一个搜索聚合请求,是如何拆分成底层的 Lucene 请求

执行步骤:

  1. 分析查询字符串,查找前50个前缀是t的词项;
  2. 只保留包含全部词项的文档,并且词项位置也相同。
GET school/student/_search
{
  "query": {
    "match_phrase_prefix": {
      "mark": {
        "query": "t",
        "slop": 1,
        "max_expansions": 50
      }
    }
  }
}

multi_match,在多个字段上执行match查询

GET school/student/_search
{
  "query": {
    "multi_match": {
      "query": "elasticsearch",
      "fields": ["mark","course","name*"]
    }
  }
}

term精确值查找

1、term 查询被用于精确值匹配,这些精确值可以是数字(number)、日期(date)、布尔值(bool)、未经过分析的字符串(keyword);
2、term 查询对于输入的文本不分析,所以它将给定的值进行精确查询。

GET school/student/_search
{
  "query": {
    "term": {
      "age": 25
    }
  }
}
GET school/student/_search
{
  "query": {
    "term": {
      "course": "spring"
    }
  }
}
GET school/student/_search
{
  "query": {
    "term": {
      "course": "spring elasticsearch"
    }
  }
}

由于term查询不需要进行查询词的分析,mapping定义中,mark字段是text,是经过词分析的,索引在倒排索引中没有happy day这个词,所以以下查询查不出任何结果

GET school/student/_search
{
  "query": {
    "term": {
      "mark": "happy day"
    }
  }
}

和match做一下对比

GET school/student/_search
{
  "query": {
    "match": {
      "mark": "happy day"
    }
  }
}

terms 查询

terms 查询和 term 查询一样,但它允许你指定多值进行匹配。
如果这个字段包含了指定值中的任何一个值,那么这个文档满足条件和 term 查询一样,terms 查询对于输入的文本不分析。

GET school/student/_search
{
  "query": {
    "terms": {
      "name": ["zhangsan","lisi"]
    }
  }
}

效果跟上边的match一样

GET school/student/_search
{
  "query": {
    "terms": {
      "mark": ["happy","day"]
    }
  }
}

range范围查询

range范围查询可以用于数字、日期等类型的字段。
gt:大于,gte:大于等于,lt:小于,lte:小于等于。

GET school/student/_search
{
  "query": {
    "range": {
      "age": {
        "gte": 20,
        "lt": 30
      }
    }
  }
}

range范围查询,可以定义日期格式

GET school/student/_search
{
  "query": {
    "range": {
      "study_date": {
        "gte": "2017-01-01",
        "lte": "2018",
        "format": "yyyy-MM-dd||yyyy"
      }
    }
  }
}

时间格式可以写成now-1d/d的形式,自动转换为前天0点

gt 大于一个日期。向上取,2014-11-18||/M -> 2014-11-30T23:59:59.999
gte 大于等于一个日期。向下取,2014-11-18||/M -> 2014-11-01
lt 小于一个日期。向下取,2014-11-18||/M -> 2014-11-01
lte 小于等于一个日期。向上取2014-11-18||/M -> 2014-11-30T23:59:59.999

GET school/student/_search
{
  "query": {
    "range": {
      "study_date": {
        "gte": "now-10d/d",
        "lt": "now+1M/d",
        "time_zone": "+08:00"
      }
    }
  }
}

搜索某个字段含有值的文档(exists)

GET school/student/_search
{
    "query": {
        "exists" : { "field" : "mark" }
    }
}

搜索某个字段没有值的文档

GET school/student/_search
{
    "query": {
        "bool": {
            "must_not": {
                "exists": {
                    "field": "mark"
                }
            }
        }
    }
}

前缀查询

GET school/student/_search
{
    "query": {
        "prefix": {
            "name": "zhang"
        }
    }
}

通配符查询(wildcard)

GET school/student/_search
{
    "query": {
        "wildcard" : { "name" : "zha*san" }
    }
}

正则表达式查询(regexp)

GET school/student/_search
{
    "query": {
        "regexp":{
            "name": "z.*san"
        }
    }
}

模糊查询,用于拼写错误的词查询(fuzzy)

GET school/student/_search
{
  "query": {
    "fuzzy": {
      "name": {
        "value": "zhangsi",
        "fuzziness": 2
      }
    }
  }
}

组合查询(constant score)

组合查询,不使用评分计算,提高效率,返回统一评分,评分为1。

GET school/student/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "mark": "day"
        }
      }
    }
  }
}

组合查询,filter过滤有缓存,全部返回评分为0

GET /school/student/_search
{
  "query": {
    "bool": {
      "filter": {
        "term": {
          "age": 25
        }
      }
    }
  }
}

bool组合查询

must:所有的语句都 必须(must) 匹配,与 AND 等价。
must_not:所有的语句都 不能(must not) 匹配,与 NOT 等价。
should:至少有一个语句要匹配,与 OR 等价。

POST /school/student/_search
{
  "query": {
    "bool": {
      "must": {
        "range": {
          "age": {"gte": 20,"lt": 30}
        }
      },
      "must_not": {
        "match": {
          "mark": "good"
        }
      },
      "should": [
        {"term": {"name": "zhangsan"}},
        {"term": {"name": "lisi"}},
        {"term": {"name": "zhaoliu"}}
      ],
      "filter": {
        "term": {
          "course": "elasticsearch"
        }
      },
      "minimum_should_match": 1
    }
  }
}

####################################

query string query

GET /school/_search
{
    "query": {
        "query_string" : {
            "query" : "+mark:zhangsan -name:aaabbb"
        }
    }
}
GET /school/_search
{
    "query": {
        "query_string" : {
            "query" : "name:(zhangsan OR lisi) AND NOT course:spring"
        }
    }
}

查询与过滤:

  1. 尽量使用Filter代替Query
    1. query搜索需要计算相关度评分并排序,无法使用缓存;
    2. filter过滤无需计算相关度评分,可以使用缓存。
  2. 尽量使用Bool组合代替AND OR
    1. bool使用must、must_not、should、filter条件可以复用,结果保存在bitset中,做交集效率高;
    2. and/or逐个文档处理、检查是否匹配,效率低。把过滤多的文档条件放在最前面。

原则上来说,使用查询语句来做全文本搜索或其他需要进行相关性评分,剩下的全部用过滤语句。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容