通过一个例子说明, 数据如下, 总共有5个数据(对应的字段名是name,类型是text):
hello world
hello Tom world
hello Tom Rob world
hello kilo
world hu
term
精确查询,搜索前不会再对搜索词进行分词,所以我们的搜索词必须是文档分词集合中的一个.
例如当搜索词是"hello world"时, 由于"hello world"并不是一个文档分词(该单词在插入索引时, 会将hello world拆成hello和world两个单词). 所以搜索结果是0.
当搜索词是hello的时候, 结果如下:
GET /test/_search
{
"query":{
"term": {
"name": {
"value": "hello"
}
}
}
}
# 结果如下
hello world
hello Tom world
hello Tom Rob world
hello kilo
那如果我想精确搜索, 类似于sql中的等于号, 该怎么办?
将name的字段类型设为keyword即可. 因为keyword类型不会对字段进行分词, 而是对整个字段进行索引.
match
会先对搜索词进行分词,分词完毕后再逐个对分词结果进行匹配(匹配的也是分词后的结果),因此相比于term的精确搜索,match是分词匹配搜索.
下面例子查询时, 句子中包含hello
或world
的都会被搜索出来, 所以这五条数据都能搜索到.
GET /test/_search
{
"query":{
"match": {
"name": "hello world"
}
}
}
# 结果
hello world
hello Tom world
hello Tom Rob world
hello kilo
world hu
match_phrase
查询时, hello和world必须相邻, 才能查出, 所以只能得到一条数据
GET /test/_search
{
"query":{
"match_phrase": {
"name": "hello world"
}
}
}
# 结果
hello world
match_phrase在查询时, 也可以使用slop参数来控制间隔多少个词条也可以被查出, 注意此处只需要间隔的词条数小于等于slop即可.
GET /test/_search
{
"query":{
"match_phrase": {
"name": {
"query": "hello world",
"slop": 1
}
}
}
}
# 结果, slop为1, 即hello world中间间隔的词条数小于等于1就符合查询条件
hello world
hello Tom world
prefix
前缀搜索. 它会对分词后的term进行前缀搜索
- 它不会分析要搜索字符串,传入的前缀就是想要查找的前缀
- 默认状态下,前缀查询不做相关度分数计算,它只是将所有匹配的文档返回,然后赋予所有相关分数值为1。它的行为更像是一个过滤器而不是查询。两者实际的区别就是过滤器是可以被缓存的,而前缀查询不行。
- 只能找到反向索引中存在的术语
原理:
需要遍历所有倒排索引,并比较每个term是否包含所指定的前缀开头.
下面的例子中如果以hell开头的term很多,那么会有严重的性能问题。但是如果term比较小,可以放心使用。
GET /test/_search
{
"query":{
"prefix": {
"name": {
"value": "hell"
}
}
}
}
# 结果
hello world
hello Tom world
hello Tom Rob world
hello kilo
wildcard
模糊查询
- 工作原理和prefix相同,只不过它并不是只比较开头,它能支持更为复杂的匹配模式。
- 它使用标准的 shell 模糊查询:? 匹配任意字符,* 匹配0个或多个字符。
Term: Doc IDs:
-------------------------
"SW50BE" | 5
"W1F7HW" | 3
"W1V3DG" | 1
"W2F8HW" | 2
"WC1N1LZ" | 4
-------------------------
GET /my_index/address/_search
{
"query": {
"prefix": {
"postcode": "W1"
}
}
}
参考文档:
https://hao5743.github.io/2019/07/11/2019-07-16/