ES中的查询操作
1、前缀查询
先输入数据:
PUT /my_index/address/1 { "postcode": "W1 3DG" } PUT /my_index/address/2 { "postcode": "W2F 8HW" } PUT /my_index/address/3 { "postcode": "W1 7HW" } PUT /my_index/address/4 { "postcode": "WC1N 1LZ" } PUT /my_index/address/5 { "postcode": "SW5 0BE" }
为了找到所有以 W1
开始的邮编,可以使用简单的 prefix
查询:
类似于SQL: select * from table where xx like 'xx%';
GET /my_index/address/_search { "query": { "prefix": { "postcode": "W1" } } }
2、短语匹配查询(match_phrase)
在执行短语匹配查询时,ElasticSearch引擎首先分析(analyze)查询字符串,从分析后的文本中构建短语查询,这意味着必须匹配短语中的所有分词,并且保证各个分词的相对位置不变:
POST /_search -d { "from":1, "size":100, "fields":[ "eventname"], "query":{ "match_phrase":{ "eventname":"Open Source" } } }
3、短语前缀匹配查询(match_phrase_prefix)
除了把查询文本的最后一个分词只做前缀匹配之外,match_phrase_prefix和match_phrase查询基本一样,参数 max_expansions 控制最后一个单词会被重写成多少个前缀,也就是,控制前缀扩展成分词的数量,默认值是50。扩展的前缀数量越多,找到的文档数量就越多;如果前缀扩展的数量太少,可能查找不到相应的文档,遗漏数据。如代码所示,能够查到eventname包含"Open Source Hack Night"的文档。
POST /_search -d { "from":1, "size":100, "fields":[ "eventname" ], "query":{ "match_phrase_prefix":{ "eventname":{ "query":"Open Source hac", "max_expansions":50 } } } }
使用match性能往往是很高的,W1–> 扫描倒排索引 –> 一旦扫描到W1,就可以停了,因为带W1的就2个doc,已经找到了 –> 没有必要继续去搜索其他的term了;
4、通配符与正则表达式查询
与 prefix
前缀查询的特性类似, wildcard
通配符查询也是一种底层基于词的查询, 与前缀查询不同的是它允许指定匹配的正则式。它使用标准的 shell 通配符查询: ?
匹配任意字符, *
匹配 0 或多个字符。
这个查询会匹配包含 W1F 7HW
和 W2F 8HW
的文档:
GET /my_index/address/_search { "query": { "wildcard": { "postcode": "W?F*HW" } } }
?
匹配 1
和 2
, *
与空格及 7
和 8
匹配。
设想如果现在只想匹配 W
区域的所有邮编,前缀匹配也会包括以 WC
开头的所有邮编,与通配符匹配碰到的问题类似,如果想匹配只以 W
开始并跟随一个数字的所有邮编, regexp
正则式查询允许写出这样更复杂的模式:
GET /my_index/address/_search { "query": { "regexp": { "postcode": "W[0-9].+" } } }
QueryBuilders.regexpQuery("postcode", "W[0-9].+");
这个正则表达式要求词必须以 W
开头,紧跟 0 至 9 之间的任何一个数字,然后接一或多个其他字符。
wildcard和regexp,与prefix原理一致,都会扫描整个索引,性能很差;数据在索引时的预处理有助于提高前缀匹配的效率,而通配符和正则表达式查询只能在查询时完成,尽管这些查询有其应用场景,但使用仍需谨慎。