Elasticsearch 全文与词项搜索

一、查询数据准备

1)创建索引

PUT student
{
  "settings":{
    "number_of_shards":1,
    "number_of_replicas":1
  },
  "mappings":{
      "properties":{
        "name":{"type":"text"},
        "address":{"type":"keyword"},
        "age":{"type":"integer"},
        "interests":{"type":"text"},
        "birthday":{"type":"date"}
    }
  }
}

2)添加测试数据

POST /student/_doc/1
{
  "name":"徐小小",
  "address":"杭州",
  "age":3,
  "interests":"唱歌 画画  跳舞",
  "birthday":"2017-06-19"
}

POST /student/_doc/2
{
  "name":"刘德华",
  "address":"香港",
  "age":28,
  "interests":"演戏 旅游",
  "birthday":"1980-06-19"
}


POST /student/_doc/3
{
  "name":"张小斐",
  "address":"北京",
  "age":28,
  "interests":"小品 旅游",
  "birthday":"1990-06-19"
}

POST /student/_doc/4
{
  "name":"王小宝",
  "address":"德州",
  "age":63,
  "interests":"演戏 小品 打牌",
  "birthday":"1956-06-19"
}

POST /student/_doc/5
{
  "name":"向华强",
  "address":"香港",
  "age":31,
  "interests":"演戏 主持",
  "birthday":"1958-06-19"
}

看是否成功

GET _cat/count/student?v

可以看出索引已经存在,并且下面有5条数据。

二、全文搜索(match查询)

match query: 知道分词器的存在,会对filed进行分词操作,然后再查询
match_all: 查询所有文档
multi_match: 可以指定多个字段
match_phrase: 短语匹配查询,ElasticSearch引擎首先分析(analyze)查询字符串,从分析后的文本中构建短语查询,这意味着必须匹配短语中的所有分词,并且保证各个分词的相对位置不变。

match搜索

match搜索会对用户给出的关键词进行解析,首先会将其进行分词处理,分词后查询语句中的任意一个词项被匹配,文档就会检索到。其子参数包含:
query(必填):搜索关键文本
analyzer(可选):分词器,用于将query中的文本转换为一个个词项
fuzziness(可选):使用编辑距离技术进行模糊匹配
prefix_length:模糊匹配的起始单词数
operator(默认为OR):布尔逻辑,用来解释query中的词项,可选的参数有OR、AND
minimum_should_match(可选):返回的文档需要匹配的最小子串数

举例
GET /student/_search
{
  "query": {
    "match": {
      "text_entry": {
        "query": "hello world", 
        "operator": "AND"
      }
    }
  }
}

查询包含text_entry字段中包含单词hello和world的文档

match_phrase搜索

match_phrase搜索会首先把query进行分词处理,分词器可以自定义,同时文档还需满足以下条件才能被匹配:
分词后所有词项都要出现在该字段中
字段中所有的词项顺序要一致

如果将上述示例改为match_phrase,那么只有world在hello后面的文档才可以被搜索到。

match_phrase_prefix搜索

和match_phrase搜索类似,只不过match_phrase_prefix支持词项的前缀匹配,例如:

举例
GET /student/_search
{
  "query": {
    "match_phrase_prefix": {
      "text_entry": {
        "query": "hell"
      }
    }
  }
}

那么只会查找出某个词项的前缀为hell的文档。

multi_match搜索

multi_match搜索是match的升级版,可以用于搜索多个字段,例如:

举例
GET /student/_search
{
  "query": {
    "multi_match": {
        "query": "hello",
        "fields": ["field1", "field2"]
    }
  }
}

上述查询语句会在field1和field2字段中查询包含单词hello的文档

match_bool_prefix搜索

match_bool_prefix搜索于Elasticsearch 7.0推出,它将输入的文本通过指定的分词器来处理多个term,然后基于这些term进行bool query,除了最后一个term使用前缀查询,其它都是使用term_query。

举例
GET /student/_search
{
  "query": {
    "match_bool_prefix": {
        "query": "away as nim",
    }
  }
}

上述示例相当于查询包含单词away、as,并且有单词以nim开头的文档。

实际操作
#1、 查询年龄为3的(命中:ID = 1)
GET student/_search
{
"query":{
   "match":{"age": 3}
   }
}

#2、查询兴趣里包含'演戏'的 (命中 ID = 2,5,4)
GET student/_search
{
  "query":{
    "match":{"interests": "演戏"}
  }
}
#这里只要interests包含'演戏','演','戏'的都会命中

#3、查询索引所有文档 (命中 ID = 1,2,3,4,5)
GET student/_search
{
  "query":{
    "match_all": {}
  }
}

#4、查询name和address包含'德' (命中 ID = 2)
GET student/_search
{
  "query":{
    "multi_match": {
      "query": "德",
      "fields":["name","address"]
    }
  }
}
#说明 这里文档ID为4的address为'德州',应该也包含'德',但却没有被命中,原因是我们索引结构中,address属性是一个keyword类型,它是需要完全匹配,而不是包含的关系。
#如果这里query为'德州'就可以命中2条数据。

#5、查询兴趣里包含'演员'的 (命中 无)
GET student/_search
{
  "query":{
    "match_phrase":{"interests": "演员"}
  }
}
# 这里和match的区别是这里是真正包含'演员',而不是只要满足其中一个字就会被模糊命中

重点 通过上面的例子有两点比较重要

  1. 文档字段属性如果是一个keyword类型,那就需要完全匹配才能命中。好比这个字段值是12345,那么你不论是1234还是123456都不会命中。

  2. 如果是match_phrase,那就是真正的包含关系。好比这个字段值是12345,那么你是1234就会命中,而123456不会命中。因为12345包含1234而不包含123456。

三、词项搜索

term query: 会去倒排索引中寻找确切的term,它并不知道分词器的存在。这种查询适合keyword 、numeric、date。

term

最基本的词项搜索,用于检索出某个text字段中包含指定单词的文档(它是相等关系而不是包含关系)。例如:

GET /student/_search
{
  "query": {
    "term": {
      "text_entry": {
        "value": "apple",
        "boost": 1.0
      }
    }
  }
}

上述请求可以查找出text_entry字段中包含单词apple的文档。
value参数为需要查找的词项;
boost用来减少或增加相关性系数,默认为1.0,大于1.0会增加其相关性,小于1.0会减少其相关性。

terms

terms可以用来查找text字段中包含一个或多个指定单词的文档,例如:

GET /student/_search
{
  "query": {
    "terms": {
      "text_entry": [
        "eye","apple"
      ]
    }
  }
}

上述请求会查找出text_entry字段中满足以下要求的文档:
包含单词eye,不包含单词apple
包含单词apple,不包含单词eye
包含单词eye和apple
同样,terms也可以使用boost来减少或增加相关性系数。

regexp

regexp检索可以查找出包含满足正则表达式单词的文档,例如:

GET /student/_search
{
  "query": {
    "regexp": {
      "text_entry": "pa.*"
    }
  }
}

上述请求会查找出text_entry字段中包含以pa开头的单词的文档。
需要注意regexp检索不支持包含^(行的开头)或$(行的结尾)的正则表达式。
regexp检索还支持以下几个参数:
flags:启用正则表达式可选运算符
max_determinized_states :查询所需的最大自动机状态数,用于限制过于复杂的正则表达式,默认10000。

prefix

prefix检索可以查找出包含指定字符串开头的单词的文档,例如:

GET /student/_search
{
  "query": {
    "prefix": {
      "text_entry": {
        "value": "par"
      }
    }
  }
}

上述请求会查找出包含以par开头的单词的文档。

range

range: 实现范围查询
include_lower: 是否包含范围的左边界,默认是true
include_upper: 是否包含范围的右边界,默认是true
range检索可以用于查询指定字段中在指定范围内的文档,例如:

#1、查询生日的范围 (命中 ID = 2,4,5)
GET student/_search
{
    "query": {
        "range": {
            "birthday": {
                "from": "1950-01-11",
                "to": "1990-01-11",
                 "include_lower": true,
                "include_upper": false
            }
        }
    }
}

#2、查询年纪18到28 (命中 ID = 2,3)
GET student/_search
{
    "query": {
        "range": {
            "age": {
                "from": 18,
                "to": 28,
                "include_lower": true,
                "include_upper": true
            }
        }
    }
}
wildcard

允许使用通配符* 和 ?来进行查询
* 代表0个或多个字符
? 代表任意一个字符

#1、查询姓名'徐'开头的 (命中 ID = 1)
GET student/_search
{
    "query": {
        "wildcard": {
             "name": "徐*"
        }
    }
}

#查不到数据 
GET student/_search
{
    "query": {
        "wildcard": {
             "name": "徐小?"
        }
    }
}
#疑惑:按照正常我觉得这里是可以查到数据的,因为有个name为'徐小小'可以匹配,估计是因为是中文的原因,所以没有匹配到

此外wildcard也支持boost参数,作用类似。

fuzzy

fuzzy检索用于词项的近似检索,例如applx可以检索出包含apple单词的文档,两个单词的相似度通过编辑距离算法(Levenshtein)确定。例如:

GET /student/_search
{
  "query": {
    "fuzzy": {
      "text_entry": "applx"
    }
  }
}

上述请求可以查找出包含近似applx单词的文档,例如包含apple、apply的文档等。
fuzzy查询效率不高,需要消耗的资源比较大。

附件搜索技巧

1. 控制查询返回的数量
#返回前两条数据 (命中: ID = 2,5)
GET student/_search
{
  "from":0,
  "size":2,
  "query":{
    "match":{"interests": "演戏"}
  }
}
2. 指定返回的字段
GET student/_search
{
  "_source":["name","age"],
  "query":{
    "match":{"interests": "演戏"}
  }
}
3. 显示要的字段、去除不需要的字段、可以使用通配符*
GET student/_search
{
  "query":{
    "match_all": {}
  },
  "_source":{
     "includes": "addr*",
     "excludes": ["name","bir*"]
  }
}
4.排序
GET student/_search
{
  "query":{
    "match_all": {}
  },
 "sort":[{
        "age":{"order": "desc"}
      }]
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。