查询都是写在"query"字段中的,可以使用get请求,如果携带的查询参数较多,也常常使用post请求,将请求参数放在请求体中。
结构化搜索(structured search) 是指查询具有内在结构的数据,常用于number, date, keyword等有固定格式的数据类型的查询。
结构化查询只是简单的对文档包括或排除处理,是精确匹配,不关心相关度|评分,得到的结果总是“非是即否”,要么存在集合中,要么存在集合外。对于结构化文本来说,一个值要么相等,要么不等,没有“相似”这种概念。
term不分词,是精确匹配
匹配文本字段(keyword或text)时,如果搜索关键字是单个字、字母,直接返回空文档如果匹配的是keyword字段,完全等价才算匹配,eg.“苹果"只能匹配"苹果”,不能匹配"红富士苹果"、“冰糖心苹果”如果匹配的是text字段,包含搜索的关键字就算匹配,不用完全等价,eg. “苹果"可以匹配"苹果”、“红富士苹果”、“冰糖心苹果”如果匹配的是float之类的数值型字段,以数值的实际大小进行比较,eg. 15.00、15认为是匹配的。 GET /mall/_search { "query": { "term": { "goods_name": "苹果" #"goods_price": 15 } } }term搜索关键字的值可以直接写,“goods_price”: “苹果”;也可以写成对象形式 “goods_name”: {“value”=“苹果”}。
terms的用法、效果和term差不多,只是值要写成数组形式
GET /mall/_search { "query":{ "terms":{ "goods_name":["梨子","桃子"] #值写成数组形式,只要匹配数组中的任意一个元素,就认为该文档匹配 } } }term、terms都只能检索一个字段,不能同时检索多个字段。
返回数据示例
{ "took": 2, #take的过去式,搜索花费的时间,ms "timed_out": false, #本次搜索是否超时 "_shards": { #分片信息 "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { #查询结果 "total": { #结果统计 "value": 2, #匹配的文档数 "relation": "eq" #匹配标准 }, "max_score": 1.0, #结果中最大的得分。es会根据相关性对匹配的文档打分,数值越大匹配度越高 "hits": [ { "_index": "mall", #所属index "_type": "_doc", #所属type "_id": "2", #文档id "_score": 1.0, #得分 "_source": { #文档中存储中的数据 "goods_name": "桃子", "goods_price": 3.0, "goods_description": "新鲜桃子,3元一斤" } }, { "_index": "mall", "_type": "_doc", "_id": "3", "_score": 1.0, "_source": { "goods_name": "梨子", "goods_price": 5.0, "goods_description": "新鲜桃子,5元一斤" } } ] } }
时间范围
GET /blog/_search { "query": { "range": { "birthDay": { # "gte": "2020-01-01", #可以只写一个限制条件 "lte": "2020-12-31" } } } } #可以使用预定义的值 "gt" : "now-1h" #过去一小时 "gt" : "2020-01-01 00:00:00||+1M" #如果是具体时间日期的基础上增减,要放在双管符号||后面
添加文档时没有传递某个字段,会使该字段没有值,有时查询时可能要筛选指定字段是否为空
GET /mall/_search { "query": { "exists": { "field": "goods_description" #指定字段有值(存在)即可 } } }missing的使用方式和exists相同,但查询的是指定字段没有值(不存在)的文档。
正则表达式的语法与平时使用的不太一样,比如不能使用\w之类的规则,具体可参考 https://www.elastic.co/guide/en/elasticsearch/reference/current/regexp-syntax.html
全文搜索(full-text search) :计算相关性,返回相关(相似)的文档。
相关性(Relevance):用于衡量搜索关键字、文档之间的匹配程度,数值越大越匹配。
结构化搜索是精确匹配,要包含搜索关键字;全文搜索注重相关性,只要相关(相似)就认为匹配。
效果和match相同,区别是会在指定的多个字段中检索,只要其中一个字段匹配,就认为文档匹配。
使用方式和match一样,区别是match_phrase把搜索关键字作为一个短语处理,不分词。
使用方式、效果和match_phrase基本相同,区别是match_phrase_prefix只能对文本字段使用。
term、match是最常用的2个查询,term主要用于匹配keyword类型的字段,match主要用于匹配text类型的字段。
共同点
匹配文本字段(keyword或text)时,如果搜索关键字是单个字、字母,直接返回空文档匹配keyword字段时都是完全匹配(都不分词),要与搜索关键字完全相同才算匹配匹配text字段时都是包含匹配,只要包含就匹配匹配数值型字段时以数值的实际大小进行比较,数值相等就算匹配后3条是由字段类型的性质决定的,和使用的查询方法无关。
不同点
匹配text类型时:term不分词,要包整个搜索关键字才算匹配;match要分词,包含搜索关键字分词得到的任意一个词项就算匹配
布尔查询又叫做组合查询,可以组合多个查询条件
must:必须满足其中的条件(都要满足)must_not:不能满足其中任意条件(都不要满足)should:可选条件(满不满足均可)filter:过滤器,常用于对查询结果进行筛选过滤,或者跳过评分阶段、加快查询速度 GET /mall/_search { "query": { "bool": { "must": [ #如果只有一个条件,可以缺省外围的数组符号[] {"match": {"goods_name": "苹果"}} ], "should": [ {"match": {"goods_decription": "冰糖心"}}, {"match": {"goods_decription": "红富士"}} ] } } } #过滤查询结果(依然会打分) GET /mall/_search { "query": { "bool": { #放在bool中 "must": { "match": {"goods_description": "苹果"} }, "filter": { #对前面得到的查询结果进行过滤 "range": { "goods_price": {"lt": 30} } } } } } #跳过评分阶段,常用于match等不关注评分的查询。返回的评分均为默认值0.0 GET /mall/_search { "query": { "bool": { #放在bool中 "filter": [ #将查询放在filter中,如果只有一个查询条件,可以缺省外层的数组符号[] {"match": {"goods_description": "苹果"}} ] } } }
使用lucene的查询语法构造⼀个查询字符串进行查询,es接到请求后,通过解析器获取查询字符串,⽣成对应的查询。
GET /mall/_search { "query": { "query_string": { "default_field": "goods_description", #default_field只能指定单个字段,多个字段用fields #"fields": ["goods_name"], "query": "生抽 or 老抽 or 酱油" #查询关键字,and、or 不区分大小写 } }, "size": 10 } #也可以直接在原来的match查询上实现 GET /mall/_search { "query": { "match": { "goods_name": { "query": "生抽 老抽 酱油", #关键字 "operator": "or" } } }, "size": 10 } query_string查询keyword字段时,要与query完全等价才算匹配,不分词,不会检测关键字and、or。query_string查询text字段时,会检测关键字and、or,以and、or为分割符将查询关键字划分为多个子串,再对这些子串使用match进行匹配。and表示所有子串都匹配才算匹配,or表示任一子串匹配就算匹配。
es内置的6种分词器
standard:默认的分词器,在空格、符号、中文字符处切,中文会切割为一个一个的汉字simple:在空格、符号、阿拉伯数字处切stop:在空格、符号、阿拉伯数字、英文介词|冠词 处切whitespace:只在空格处切language:根据语言的语法规则来切,常见的有 english、chinese,这2种的效果都一样:在空格、符号、英文介词|冠词 处切,中文切割为一个一个的汉字。pattern:根据正则表达式来切,默认使用的正则表达式是\W+,在匹配\W+的地方切es内置的分词器对中文分词支持较差,常使用第三方的中文分词器
smartcn:SmartCN,支持中文、中英文混合文本的分词ik_max_word:ik分词器,比SmartCN更智能,推荐此外还有拼音分词器、ip分词器等
插件下载地址:https://www.elastic.co/guide/en/elasticsearch/plugins/current/analysis.html
linux、win都是下载zip,插件版本尽量与es版本保持一致。
可以本地解压后上传到es的plugins目录下,也可以上传到es的plugins目录后再解压
#如果没有unzip命令,可以自己安装 yum install unzip #-d指定解压目录,未指定时默认解压到当前目录下 unzip elasticsearch-analysis-ik-7.10.0.zip -d elasticsearch-analysis-ik-7.10.0 #需删除原来的压缩包 rm -I elasticsearch-analysis-ik-7.10.0.zip安装插件:放在plugins目录下,卸载插件:从plugins目录中移除。
重启es生效
在定义mapping时给文本字段指定分词器,该字段查询要分词时会自动使用指定的分词器分词
PUT /mall { "mappings": { "properties": { "goods_name": { "type": "keyword" }, "goods_price": { "type": "float" }, "goods_description": { "type": "text", "analyzer": "ik_max_word" #在mapping中指定分词器时,只能给text类型的字段指定分词器,不能给keyword指定分词器 } } } }ik分词器有2种模式
ik_max_word:分词粒度细,检索结果中往往包含了关联性不大的条目。eg.小米笔记本 => 小米、笔记本、笔记、本ik_smart:分词力度粗,检索结果的相关性大,用得较多。eg. 小米笔记本 => 小米、笔记本
查询时可以指定分词器
GET /mall/_search { "query": { "match": { "goods_name": { "query": "苹果汁", "analyzer": "ik_max_word" #指定要使用的分词器,查询时可以对keyword、text类型指定分词器 } } } }
查看分词结果
GET /_analyze { "analyzer": "ik_max_word", #指定要使用的分词器 "text": "小米笔记本" }分词器优先级:查询语句中指定的分词器 > mapping中指定的分词器 > 未指定时默认的standard分词器
高亮显示只是给结果中的关键字加上指定标签,代替原来的内容。开始、结束标签缺省时默认为<em></em>。
对于match等要使用分词器的查询,是把分词后得到的词作为关键字加标签,eg. “mac pro”分词为“mac”、“pro”,匹配到的“mac pro 16英寸”会变成“<em>mac</em> <em>pro</em> 16英寸”。一般加行内标签,不加块级标签。
es有3个建议器(suggester)
term suggester: 词条建议器,对输入的搜索关键字分词,对每个词(term)进行模糊查询提供对应的词项建议phrase suggester:短语建议器,在term的基础上,会考量多个term之间的关系,⽐如是否同时出现在索引的原⽂⾥,相邻程度,以及词频等completion suggester:自动补全建议器前2个可以实现自动纠错,第三个可以实现补全提示
GET /mall/_search { "suggest": { "goods_name_suggest": { #自定义的suggest名称 "text": "苹果", #要搜索的关键字 "term": {"field": "goods_name"} #要使用的建议器、要检索的字段 } } }
数据聚合即数据的统计分析。常见的聚合方式如下
桶聚合:对数据进行分组,相当于sql的group by指标聚合:对数据集使用max() 、min()、avg()、sum()之类的聚合函数,统计最大值、最小值、平均值、总量等指标主要概念
桶(bucket):满足特定条件的文档集合,实质是基于条件来划分文档指标(metric):数据集的一些特征值,比如最大值、最小值、平均值支持嵌套,桶聚合可以嵌套桶聚合、指标聚合,指标聚合也可以嵌套桶聚合、指标聚合。
对于嵌套的聚合,es只需遍历一次数据,不用多次循环遍历数据,速度快、性能高,但聚合、排序都很耗内存。
聚合可以对index中的所有文档使用,也可以对查询结果使用。
聚合文本类型时要注意:只能对keyword字段使用聚合,不能对text字段使用聚合,如果对text使用聚合,会报错
Text fields are not optimised for operations that require per-document field data like aggregations and sorting, so these operations are disabled by default
text存储的是文章内容、评论之类的长文本,没必要聚合,定义mapping时要严格区分keyword、text字段。
常用的聚合函数
value_count 该字段有值(不为空)的文档数maxminavgsumstats 同时统计以上5个指标extended_stats 统计更多的信息,比如平⽅和、⽅差、标准差cardinality 去重计数 #对全样数据进行聚合,eg. 统计nba球员的平均年龄 GET /nba/_search { "aggs": { "avg_age": { #自定义的聚合名称 "avg": { #要使用的聚合函数 "field": "age" #要统计的字段 } } }, "size": 0 } #对查询结果进行聚合,eg. 统计⽕箭队球员的平均年龄 GET /nba/_search { "query": { "term": { "team_name": "火箭队" } }, "aggs": { "avgAge": { "avg": { "field": "age" } } }, "size": 0 } #去重计数,eg. 统计某个活动的中奖人数 POST /raffle/_search { "query": { "term": { "activity_id": 123 } }, "aggs": { "coun_user": { "cardinality": { "field": "user_id" } } }, "size": 0 }
返回值示例
"25.0" : 68, # <=68分的占25.0% "50.0" : 80.5, # <=80.5分的占50.0% "75.0" : 92 # <=92分的占75.0%
聚合能把统计结果转换成易于显示为图表的数据,方便前端展示
#eg. 统计学生成绩的分布情况。也属于桶聚合 GET /student/_search { "aggs":{ "socre_info":{ "histogram":{ "field": "score", "interval": 20 #指定间距。[0,20),[20,40)...一个区间一个桶,区间上有文档时才划分为桶 } } }, "size" : 0 } #按成绩划分区间(桶),统计每个区间上的文档,再计算每个桶内的平均分。桶聚合+指标聚合 GET /student/_search { "aggs": { "socre_info": { "histogram": { "field": "score", "interval": 20 }, "aggs": { "avg_score": { "avg": { "field": "score" } } } } }, "size": 0 }返回值示例
"aggregations" : { "socre_info" : { "buckets" : [ { "key" : 40.0, # [40, 60) 有4人,4人平均分50.5 "doc_count" : 4, "avg_score" : { "value" : 50.5 } }, { "key" : 60.0, # [60, 80) 有20人,21人平均分72 "doc_count" : 21, "avg_score" : { "value" : 72.0 } }, { "key" : 80.0, # [80, 100) 有9人,9人平均分89 "doc_count" : 9, "avg_score" : { "value" : 89.0 } } ] #没有[100, 120) 这个桶,说明无人考满分 } }