字符串
主要包括: text和keyword两种类型,keyword代表精确值不会参与分词,text类型的字符串会参与分词处理
数值
包括: long, integer, short, byte, double, float
布尔值
boolean
时间
date
数组
数组类型不需要专门定义,只要插入的字段值是json数组就行
GEO类型
主要涉及地理信息检索、多边形区域的表达
text类型,支持全文搜索,因为text涉及分词,所以可以配置使用什么分词器,尤其涉及中文分词。
实际项目中,如果不需要模糊搜索的字符类型,可以选择keyword类型,例如:手机号、email、微信的openid等等,如果选text类型,可能会出现搜出一大堆相似的数据,而且不是精确的数据。
query子句主要用于编写查询条件,类似于SQL中的where语句。
query子句主要用于编写类似SQL的where语句,支持布尔查询(and/or)、IN、全文搜索、模糊匹配、范围查询(大于/小于)。
其中:text类型字段支持分词,可以使用模糊查询。keyword类型只能做等值查询,不能进行分词。
使用match实现全文搜索。类似于SQL中的like操作。
简单使用的语法:
- GET /{索引名}/_search
- {
- "query": {
- "match": {
- "{FIELD}": "{TEXT}"
- }
- }
- }
说明:
{FIELD} - 就是我们需要匹配的字段名
{TEXT} - 就是我们需要匹配的内容
例子:
- GET /article/_search
- {
- "query": {
- "match" : {
- "title" : "ES教程"
- }
- }
- }
article索引中,title字段匹配“ES教程”的所有文档。
如果title字段的数据类型是text类型,搜索关键词会进行分词处理。
等价SQL(假设"ES教程"没有进行分词):
select * from article where title like '%ES教程%'
例子:
- GET /article/_search
- {
- "query": {
- "multi_match": {
- "query": "斯柯达前轮制动器",
- "fields":[
- "doc_title",
- "doc_content"
- ]
- }
- }
- }
等价SQL:
select * from article where doc_title like '%<斯柯达前轮制动器的分词>%' or doc_content like '%<斯柯达前轮制动器的分词>%'
因为 斯柯达前轮制动器的分词 会有很多,所以实际上也会有很多的like,而不仅仅是上面的两个like。
match_phrase查询是ES中一种用于精确匹配短语的查询方式,可以确保查询字符串中的关键词按照给定的顺序在文档中连续出现。
说明:检索词还是进行分词的,分词后的各个单词的顺序在 被检索的文中是一样的。
例子:
- GET /article/_search
- {
- "query": {
- "match_phrase": {
- "doc_content": "制动器装配"
- }
- }
- }
搜索结果:
指定分词匹配的布尔规则,默认情况下operator为or,即分词中有一个匹配即可。
当operator为and时,需要文档匹配所有的分词。
例子:
- GET demo_idx/_search
- {
- "query": {
- "match": {
- "content": {
- "query": "simple rest apis distributed nature",
- "operator": "and"
- }
- }
- }
- }
我们希望精确匹配在搜索结果中排名较高,但也希望看到结果中相关性较低的文档,此时使用should子句来组合OR、AND和match短语查询。布尔查询中的should子句采用更好匹配的方法,因此每个子句的得分将为每个文档的最终_score做出贡献。
- GET demo_idx/_search
- {
- "query": {
- "bool": {
- "should": [
- {
- "match": {
- "content": {
- "query": "simple rest apis distributed nature"
- }
- }
- },
- {
- "match": {
- "content": {
- "query": "simple rest apis distributed nature",
- "operator": "and"
- }
- }
- },
- {
- "match_phrase": {
- "content": {
- "query": "simple rest apis distributed nature",
- "boost": 2
- }
- }
- }
- ]
- }
- }
- }
使用term实现精确匹配。
如果想要类似SQL语句中的等值匹配,不需要进行分词处理,例如:订单号、手机号、时间字段,不需要分值处理,只要精确匹配。
语法:
- GET /{索引名}/_search
- {
- "query": {
- "term": {
- "{FIELD}": "{VALUE}"
- }
- }
- }
{FIELD} - 就是我们需要匹配的字段名
{VALUE} - 就是我们需要匹配的内容,除了TEXT类型字段以外的任意类型。
例子:
- GET /order_v2/_search
- {
- "query": {
- "term": {
- "order_no": "202003131209120999"
- }
- }
- }
搜索订单号order_no = "202003131209120999"的文档。
类似SQL语句:
select * from order_v2 where order_no = "202003131209120999"
如果我们要实现SQL中的in语句,一个字段包含给定数组中的任意一个值就匹配。
语法:
- GET /order_v2/_search
- {
- "query": {
- "terms": {
- "{FIELD}": [
- "{VALUE1}",
- "{VALUE2}"
- ]
- }
- }
- }
说明:
{FIELD} - 就是我们需要匹配的字段名
{VALUE1}, {VALUE2} … {VALUE N} - 就是我们需要匹配的内容,除了TEXT类型字段以外的任意类型。
例子:
- GET /order_v2/_search
- {
- "query": {
- "terms": {
- "shop_id": [123,100,300]
- }
- }
- }
搜索order_v2索引中,shop_id字段,只要包含[123,100,300]其中一个值,就算匹配。
类似SQL语句:
select * from order_v2 where shop_id in (123,100,300)
通过range实现范围查询,类似SQL语句中的>, >=, <, <=表达式。
语法:
- GET /{索引名}/_search
- {
- "query": {
- "range": {
- "{FIELD}": {
- "gte": 10,
- "lte": 20
- }
- }
- }
- }
参数说明:
{FIELD} - 字段名
gte范围参数 - 等价于>=
lte范围参数 - 等价于 <=
范围参数可以只写一个,例如:仅保留 “gte”: 10, 则代表 FIELD字段 >= 10
范围参数如下:
- gt - 大于 ( > )
- gte - 大于且等于 ( >= )
- lt - 小于 ( < )
- lte - 小于且等于 ( <= )
例子:
- GET /order_v2/_search
- {
- "query": {
- "range": {
- "shop_id": {
- "gte": 10,
- "lte": 200
- }
- }
- }
- }
查询order_v2索引中,shop_id >= 10 且 shop_id <= 200的文档。类似SQL:
select * from order_v2 where shop_id >= 10 and shop_id <= 200
前面的例子都是设置单个字段的查询条件,如果想要编写类似SQL的Where语句组合多个字段的查询条件,可以使用bool语句。
语法:
- GET /{索引名}/_search
- {
- "query": {
- "bool": { // bool查询
- "must": [], // must条件,类似SQL中的and, 代表必须匹配条件
- "must_not": [], // must_not条件,跟must相反,必须不匹配条件
- "should": [] // should条件,类似SQL中or, 代表匹配其中一个条件
- }
- }
- }
must、must_not和should条件的参数都是一个数组,意味着他们都支持设置多个条件。
同时,前面介绍的单个字段的匹配语句,都可以用在bool查询语句中进行组合。
类似SQL的and,代表必须匹配的条件。
语法:
- GET /{索引名}/_search
- {
- "query": {
- "bool": {
- "must": [
- {匹配条件1},
- {匹配条件2},
- ...可以有N个匹配条件...
- ]
- }
- }
- }
例子:
- GET /order_v2/_search
- {
- "query": {
- "bool": {
- "must": [
- {
- "term": {
- "order_no": "202003131209120999"
- }
- },
- {
- "term": {
- "shop_id": 123
- }
- }
- ]
- }
- }
- }
这里的Must条件,使用了term精确匹配,等价SQL:
select * from order_v2 where order_no="202003131209120999" and shop_id=123
跟must的作用相反,语法类似。
类似SQL中的 or, 只要匹配其中一个条件即可。
语法:
- GET /{索引名}/_search
- {
- "query": {
- "bool": {
- "should": [
- {匹配条件1},
- {匹配条件2},
- …可以有N个匹配条件…
- ]
- }
- }
- }
例子:
- GET /order_v2/_search
- {
- "query": {
- "bool": {
- "should": [
- {
- "term": {
- "order_no": "202003131209120999"
- }
- },
- {
- "term": {
- "order_no": "22222222222222222"
- }
- }
- ]
- }
- }
- }
等价SQL:
select * from order_v2 where order_no="202003131209120999" or order_no="22222222222222222"
- GET /order_v2/_search
- {
- "query": {
- "bool": {
- "should": [
- {
- "bool": {
- "must": [
- {
- "term": {
- "order_no": "2020031312091209991"
- }
- },
- {
- "range": {
- "shop_id": {
- "gte": 10,
- "lte": 200
- }
- }
- }
- ]
- }
- },
- {
- "terms": {
- "tag": [
- 1,
- 2,
- 3,
- 4,
- 5,
- 12
- ]
- }
- }
- ]
- }
- }
- }
等价SQL:
select * from order_v2 where (order_no='202003131209120999' and (shop_id>=10 and shop_id<=200)) or tag in (1,2,3,4,5)
wildcard 关键字: 通配符查询 ? 用来匹配一个任意字符 * 用来匹配多个任意字符。
例子:
- GET /xizi/emp/_search
- {
- "query": {
- "wildcard": {
- "name": {
- "value": "xi*"
- }
- }
- }
- }
fuzzy 模糊查询,最大模糊错误必须在0-2之间
搜索关键词长度为 2 不允许存在模糊 0
搜索关键词长度为3-5 允许一次模糊 0 1
搜索关键词长度大于5 允许最大2模糊
例子:
- GET /xizi/emp/_search
- {
- "query": {
- "fuzzy": {
- "name":"xizi"
- }
- }
- }
例子1:
- get lib3/user/_search
- {
- "_source":["name","age"],
- "query":{
- "match": {
- "interests": "changge"
- }
- }
结果只返回索引中name和age字段信息
例子2:
- get lib3/user/_search
- {
- "query":{
- "match_all": {}
- },
- "_source":{
- "includes": "addr*",
- "excludes": ["name","bir*"]
- }
- }
显示要的字段、去除不需要的字段、可以使用通配符*。
boost值控制每个查询子句的相对权重,该值默认为1。
boost参数被用来增加一个子句的相对权重(当boost大于1时),或者减小相对权重(当boost介于0到1时),但是增加或者减小不是线性的。换言之,boost设为2并不会让最终的_score加倍。
例子:
- GET/_search{
- "query": {
- "bool": {
- "must": {
- "match": {
- "content": {
- "query": "full text search",
- "operator": "and"
- }
- }
- },
- "should": [{
- "match": {
- "content": {
- "query": "Elasticsearch",
- "boost": 3
- }
- }
- },
- {
- "match": {
- "content": {
- "query": "Lucene",
- "boost": 2
- }
- }
- }]
- }
- }
- }
例子:
- get data_info/_search
- {
- "_source":["doc_title","doc_content"],
- "query": {
- "match": {
- "doc_content": "斯柯达前轮制动器"
- }
- },
- "highlight":{
- "fields":{
- "doc_content":{}
- }
- }
- }
返回结果:
ES默认返回10条结果。
例子:
- get data_info/_search
- {
- "query": {
- "match": {
- "doc_content": "斯柯达前轮制动器"
- }
- },
- "size": 2
- }
结果中只有2条信息。
from 关键字: 用来指定起始返回位置,和size关键字连用可实现分页效果。
例子:
- get data_info/_search
- {
- "query": {
- "match": {
- "doc_content": "斯柯达前轮制动器"
- }
- },
- "size": 2,
- "from": 3
- }
使用该属性会让得分失效。
例子:
- GET /db_idx4/_search
- {
- "query":{
- "match_all":{
-
- }
- },
- "sort":[
- {
- "age":"desc"
- }
- ]
- }
ES提供了一个解释性API和一个解释性查询参数以了解如何计算分数。
例子:
- GET /db_idx4/_search
- {
- "explain": true,
- "query": {
- "match_phrase": {
- "doc_content": "制动器装配"
- }
- }
- }
结果示例:
平时我们使用SQL like语句搜索一些文本、字符串是否包含指定的关键词,如果两篇文章都包含我们的关键词,那么具体哪篇文章内容的相关度更高?这个SQL的like语句是做不到的,更别说like语句的性能问题了。
ES通过分词、相关度计算可以解决这个问题,ES内置了一些相关度算法,大致上意思是:如果一个关键词在一篇文章出现的频率高,并且在其他文章中出现少,那说明这个关键词与这篇文章的相关度很高。
ES对于text类型的字段,在插入数据的时候,会进行分词处理,然后根据分词的结果索引文档,当我们搜索text类型字段的时候,也会先对搜索关键词进行分词处理、然后根据分词的结果去搜索。
ES使用的默认评分算法是BM25,决定文档得分的3个主要因素:
function_score和script_score是很耗资源的,所以实际使用时只需要计算一组经过过滤的文档的分数。
script_score定制的例子:
- GET best_games/_search
- {
- "_source": [
- "name",
- "critic_score",
- "user_score"
- ],
- "query": {
- "script_score": {
- "query": {
- "match": {
- "name": "Final Fantasy"
- }
- },
- "script": {
- "source": "_score * (doc['user_score'].value*10+doc['critic_score'].value)/2/100"
- }
- }
- }
- }
具体细节参考:Elasticsearch:使用 function_score 及 script_score 定制搜索结果的分数-CSDN博客
语法:
- GET /_analyze
- {
- "text": "需要分词的内容",
- "analyzer": "分词器"
- }
例子:
- GET http://xx.elasticsearch.aliyuncs.com:9200/_analyze
- {
- "text":"上海大学",
- "analyzer": "standard"
- }
使用standard分词器,对"上海大学"进行分词,下面是输出结果:
- {
- "tokens": [
- {
- "token": "上",
- "start_offset": 0,
- "end_offset": 1,
- "type": "
", - "position": 0
- },
- {
- "token": "海",
- "start_offset": 1,
- "end_offset": 2,
- "type": "
", - "position": 1
- },
- {
- "token": "大",
- "start_offset": 2,
- "end_offset": 3,
- "type": "
", - "position": 2
- },
- {
- "token": "学",
- "start_offset": 3,
- "end_offset": 4,
- "type": "
", - "position": 3
- }
- ]
- }
token就是分解出来的关键词。
同样是按条件匹配,filter不统计相关度,must统计相关度。就是filter不计算score分数值,而must是计算的。所以must比filter计算更复杂、更耗时。
具体参考:Elasticsearch Query: filter与must的区别_elasticsearch must 和filter的区别-CSDN博客