一、查询数据准备
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的区别是这里是真正包含'演员',而不是只要满足其中一个字就会被模糊命中
重点
通过上面的例子有两点比较重要
文档字段属性如果是一个
keyword
类型,那就需要完全匹配才能命中。好比这个字段值是12345
,那么你不论是1234
还是123456
都不会命中。如果是
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"}
}]
}