前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >017.Elasticsearch搜索操作入门篇

017.Elasticsearch搜索操作入门篇

作者头像
CoderJed
发布2020-07-06 15:49:14
1.2K0
发布2020-07-06 15:49:14
举报
文章被收录于专栏:Jed的技术阶梯Jed的技术阶梯

1. 多种搜索方式

1.1 Query String Search:在请求URL中包括search的参数

代码语言:javascript
复制
# 语法
curl -X GET "ip:port/index_name/type_name/_search?q=key1=value1&key2=value2"

# 举例
# 查看全部文档
curl -X GET "node01:9200/shop/product/_search"
# 搜索商品名称中包含“Toothpaste”的商品,而且按照price降序排序
curl -X GET "node01:9200/shop/product/_search?q=name:Toothpaste&sort=price:desc"

# 扩展
GET /index_name/type_name/_search?q=key:value
GET /index_name/type_name/_search?q=+key:value
GET /index_name/type_name/_search?q=-key:value

# name的值包含"Tom"
GET /test_index/test_type/_search?q=name:Tom
# 无论那个field,只要其值包含"Tom"即可
GET /test_index/test_type/_search?q=Tom
# =+ 与 = 的效果相同
GET /test_index/test_type/_search?q=+name:Tom
# =- 的意思是:field不是指定的字符串(精确匹配,例如本例子不会过滤name=Tommy的document)
GET /test_index/test_type/_search?q=-name:Tom
  • "q=value"原理分析

假设有如下的document:

代码语言:javascript
复制
{
    "name": "Tom",
    "age": 25,
    "sex": "male",
    "country": "China"
}

在插入这条数据后,ES会自动将多个field的值,全部用字符串的方式串联起来,组成一个长字符串,作为_all field的值,同时建立索引,本例中,"_all field"="Tom 25 male China",当使用Query String Search:GET /test_index/test_type/_search?q=Tom,实际上并不会去逐一比较每个field的值,而是直接与"_all field"的分词结果做比较

  • Query String Search的适用场景

适用于临时的在命令行使用一些工具,比如curl,快速的发出请求,来检索想要的信息;但是如果查询请求很复杂,是很难去构建的,在生产环境中,几乎很少使用Query String Search

1.2 Query DSL(Domain Specified Language):查询领域专用语言

  • 适用场景:更加适合生产环境的使用,可以构建复杂的查询
  • 基本语法 GET /index_name/type_name/_search?key=value { "key1": "value1" } # 说明: # 1.HTTP协议,一般不允许get请求带上request body,但是因为get更加适合描述查询数据的操作,因此还是这么用了 # 2.很多浏览器或服务器都支持GET+request body模式,如果不支持,也可以用POST /_search,例如 GET /index1/type1/_search?from=0&size=2 POST /index1/type1/_search { "from": 0, "size": 2 } # 3.查询条件的json中,可以进行复杂的json嵌套,来实现复杂的搜索
  • 入门案例 # 查询某索引的全部文档 GET /myindex/my_type/_search { "query": { "match_all": {} } }
  • timeout参数 GET /myindex/my_type/_search?timeout=1s { "query": { "match_all": {} } } 查询的时候可以指定一个timeout参数,默认没有值,这个timeout比较特殊,是说,最多查询指定的时间,比较index总共有1万条数据,全部查询出来需要1min,那么用户体验肯定是不好的,设置timeout为1s,就是说,在1s秒内,能查到多少就给我返回多少,当然了能全部返回是最好的,常用的单位有毫秒(ms)、秒(s)、分钟(m)

1.3 查询结果元数据分析

代码语言:javascript
复制
{
  "took": 6,
  "timed_out": false,
  "_shards": {
    "total": 6,
    "successful": 6,
    "failed": 0
  },
  "hits": {
    "total": 10,
    "max_score": 1,
    "hits": [
      {
        "_index": ".kibana",
        "_type": "config",
        "_id": "5.2.0",
        "_score": 1,
        "_source": {
          "buildNum": 14695
        }
      }
    ]
  }
}
  • took:整个搜索请求花费了多少毫秒
  • hits.total:本次搜索,返回了几条结果
  • hits.max_score:本次搜索的所有结果中,最大的相关度分数是多少,这个分数越大,排名越靠前,说明这条文档越符合搜索条件
  • hits.hits:默认查询前10条数据,按照"_score"降序排序
  • shards.total:此文档在几个shard上存在(包括主分片和其副本)
  • shards.successful:在这些shard上请求这条数据,可以响应的shard的个数
  • shards.failed:在这些shard上请求这条数据失败的shard个数
  • hits.hits._index:文档所属index
  • hits.hits._type:文档所属type
  • hits.hits._id:文档id
  • hits.hits._source:文档内容

2. 词条查询(term)和全文检索(full text)

  • 词条查询:词条查询不会分析查询条件,只有当词条和查询字符串串完全匹配时,才匹配搜 索。
  • 全文查询:ElasticSearch引擎会先分析查询字符串,将其拆分成多个单词,只要已分析的字 段中包含词条的任意一个,或全部包含,就匹配查询条件,返回该文档;如果不包含任意一 个分词,表示没有任何文档匹配查询条件
  • 查询结果与使用termmatch与数据本身的类型息息相关

2.1 准备测试数据

代码语言:javascript
复制
# text:用于全文检索,该类型的字段将通过分词器进行分词
# keyword:不分词,只能搜索该字段完整的值
PUT /shop
{
  "mappings": {
    "product": {
      "properties": {
        "name": {
          "type": "keyword"
        },
        "desc": {
          "type": "text"
        }
      }
    }
  }
}

PUT shop/product/1
{
    "name": "Yunnanbaiyao Toothpaste",
    "desc": "Yunnanbaiyao Toothpaste"
}

PUT /shop/product/2
{
    "name": "Darlie Toothpaste",
    "desc": "Darlie Toothpaste"
}

PUT /shop/product/3
{
    "name": "ZhongHua Toothpaste",
    "desc": "ZhongHua Toothpaste"
}

2.2 term测试

代码语言:javascript
复制
# 词条查询

# 没有结果
POST /shop/product/_search
{
    "query": {
        "term": {
            "name": "Toothpaste"
        }
    }
}

# 有结果(1条)
POST /shop/product/_search
{
    "query": {
        "term": {
            "name": "Darlie Toothpaste"
        }
    }
}

# 没有结果
POST /shop/product/_search
{
    "query": {
        "term": {
            "desc": "Toothpaste"
        }
    }
}

# 没有结果
# 这个没有结果,是因为"Darlie Toothpaste"分词后分成了"darlie"和"toothpaste"
# 所有完全匹配"Darlie Toothpaste"是无法匹配到的
POST /shop/product/_search
{
    "query": {
        "term": {
            "desc": "Darlie Toothpaste"
        }
    }
}


# 有3条结果
POST /shop/product/_search
{
    "query": {
        "term": {
            "desc": "toothpaste"
        }
    }
}

2.3 terms测试

代码语言:javascript
复制
# 没有数据
POST /shop/product/_search
{
    "query": {
        "terms": {
            "name": ["Darlie", "Toothpaste"]
        }
    }
}

# 两条结果
POST /shop/product/_search
{
    "query": {
        "terms": {
            "name": ["Darlie Toothpaste", "Yunnanbaiyao Toothpaste"]
        }
    }
}

# 一条结果
POST /shop/product/_search
{
    "query": {
        "terms": {
            "name": ["Darlie", "Yunnanbaiyao Toothpaste"]
        }
    }
}

# 没有结果
POST /shop/product/_search
{
    "query": {
        "terms": {
            "desc": ["Darlie Toothpaste", "Yunnanbaiyao Toothpaste"]
        }
    }
}

# 1个结果
POST /shop/product/_search
{
    "query": {
        "terms": {
            "desc": ["darlie", "Yunnanbaiyao Toothpaste"]
        }
    }
}

2.4 match测试

代码语言:javascript
复制
# 有结果(1条)
GET /shop/product/_search
{
    "query": {
        "match": {
            "name": "Darlie Toothpaste"
        }
    }
}

# 没有结果
GET /shop/product/_search
{
    "query": {
        "match": {
            "name": "Toothpaste"
        }
    }
}

# 有结果(3条)
GET /shop/product/_search
{
    "query": {
        "match": {
            "desc": "Toothpaste"
        }
    }
}

# 有结果(3条)
GET /shop/product/_search
{
    "query": {
        "match": {
            "desc": "Darlie Toothpaste"
        }
    }
}

2.5 multi_match测试

代码语言:javascript
复制
PUT /shop/product/5
{
    "name": "Apple Toothpaste",
    "desc": "Apple Darlie"
}

PUT /shop/product/6
{
    "name": "Orage Darlie",
    "desc": "Orage"
}

# 3条结果
POST /shop/product/_search
{
    "query": {
        "multi_match": {
            "query": "Darlie",
            "fields": ["name", "desc"]
        }
    }
}

# 4条结果
POST /shop/product/_search
{
    "query": {
        "multi_match": {
            "query": "Orage Darlie",
            "fields": ["name", "desc"]
        }
    }
}

2.6 match_phrase测试

代码语言:javascript
复制
# 有结果(1条)
POST /shop/product/_search
{
    "query": {
        "match_phrase": {
            "desc": "Darlie Toothpaste"
        }
    }
}

# 有结果(3条)
POST /shop/product/_search
{
    "query": {
        "match_phrase": {
            "desc": "Toothpaste"
        }
    }
}

# 没有结果
POST /shop/product/_search
{
    "query": {
        "match_phrase": {
            "name": "Toothpaste"
        }
    }
}

# 有结果(1条)
POST /shop/product/_search
{
    "query": {
        "match_phrase": {
            "name": "Darlie Toothpaste"
        }
    }
}

2.7 match_all测试

代码语言:javascript
复制
# 查询全部数据
POST /shop/product/_search
{
    "query": {
        "match_all": {}
    }
}

GET /shop/product/_search
{
    "query": {
        "match_all": {
            "desc": "Darlie Toothpaste"
        }
    }
}

# 结果
{
    "error":{
        "root_cause":[
            {
                "type":"parsing_exception",
                "reason":"[5:13] [match_all] unknown field [desc], parser not found","line":5,
                "col":13
            }
        ],
        "type":"parsing_exception",
        "reason":"[5:13] [match_all] unknown field [desc], parser not found",
        "line":5,
        "col":13,
        "caused_by":{
            "type":"x_content_parse_exception",
            "reason":"[5:13] [match_all] unknown field [desc], parser not found"}
        },
        "status":400
    }
}

# 分页
GET /shop/product/_search
{
    "query": {
        "match_all": {}
    },
    "from": 0,
    "size": 10
}

2.8 match_phrase_prefix测试

代码语言:javascript
复制
PUT /shop/product/7
{
    "name": "Darlie Pro Toothpaste",
    "desc": "Darlie Pro Toothpaste"
}

# 有结果(1条)
POST /shop/product/_search
{
    "query": {
        "match_phrase_prefix": {
            "name": "Darlie Toothpaste"
        }
    }
}

# 没有结果
POST /shop/product/_search
{
    "query": {
        "match_phrase_prefix": {
            "name": "Darlie"
        }
    }
}

# 有结果(2条)
POST /shop/product/_search
{
    "query": {
        "match_phrase_prefix": {
            "desc": "Darlie"
        }
    }
}

# 有结果(1条)
POST /shop/product/_search
{
    "query": {
        "match_phrase_prefix": {
            "desc": "Darlie Pro"
        }
    }
}

# 有结果(1条)
POST /shop/product/_search
{
    "query": {
        "match_phrase_prefix": {
            "desc": "Darlie Toothpaste"
        }
    }
}

2.9 总结

keyword

text

term

完全匹配才返回

完全匹配分词后的单词才返回

terms

传入多个字符串,返回那些可以完全匹配的结果

每个传入的单词,在分词后的所有单词中进行匹配,完全匹配才返回

match_all

查询全部数据,不能传入任何参数

查询全部数据,不能传入任何参数

match

完全匹配才返回

对输入字符串进行分词,指定的字段文本分词后的词语中包含任意一个输入字符串的分词词语,就算匹配,就可以作为结果返回

multi_match

指定的多个字段都完全匹配才返回

对输入字符串进行分词,指定的字段文本分词后的词语中包含任意一个输入字符串的分词词语,就算匹配,就可以作为结果返回

match_phrase

完全匹配才返回

输入字符串不分词,指定的字段文本分词后的词语中包含完整的输入字符串,才可以算匹配,才能作为结果返回

match_phrase_prefix

完全匹配才返回

输入一个单词,例如"hello",只要指定的字段文本分词后的词语中有一个词语是以"hello"作为前缀,就算匹配,输入一个短语例如"hello world tom",那么先匹配分词的后的词语中包含"hello world"的文档,然后在这些文档中过滤,只要这些文档的词语中包含以"tom"开头的词语,就算匹配

3. 范围查询

代码语言:javascript
复制
GET /company/employee/_search
{
  "query": {
    "range": {
      "age": {
        "gte": 31
      }
    }
  }
}

4. query上下文和filter上下文

  • query上下文:在搜索中,计算每个满足条件的document的相关度,进行评分,即给document的"_score"赋值,并进行倒序排序,然后返回结果,使用query上下文查询的结果无法缓存
  • filter上下文:在搜索中,只是过滤出符合条件的document,不计算相关度,使用filter上下文查询的结果将被缓存,以提高整体的查询效率,缓存不需要太多的内存,它只缓存哪些文档与此filter条件相匹配
  • 说明:这里说的query上下文和filter上下文是描述的两种现象,而非使用"query"就是query上下文,使用"filter"就是filter上下文,例如: # 既有query上下文,也有filter上下文 GET /_search { "query": { "bool": { "must": [ {"match": {"title": "Search"}}, {"match": {"content": "Elasticsearch" }} ], "filter": [ {"term": {"status": "published" }}, {"range": {"publish_date": {"gte": "2015-01-01" }}} ] } } } # 这个查询,虽然DSL语句中有"query"这个单词,但是它本质上只有一个filter上下文 GET /_search { "query" : { "bool" : { "filter" : { "term" : { "author_id" : 1 } } } } } # 这个查询也是一个filter上下文查询,并且"constant_score"规定将符合条件的document的score都设置为"bootst"指定的值 # 如果没有boost,则查询出的document的score都为1.0 GET /_search { "query": { "constant_score" : { "filter" : { "term" : { "user" : "kimchy"} }, "boost" : 1.2 } } }

一般来说,如果是进行搜索,需要将最匹配搜索条件的数据先返回,那么用query上下文;如果只是要根据条件筛选出一部分数据,不关注其排序,那么用filter,如果希望越符合搜索条件的document排名越靠前,就把这些搜索条件要放在query上下文中,如果只是想查询到数据并不关注其排名,就放到filter上下文中。

5. 多条件组合查询

代码语言:javascript
复制
# 语法
GET /index_name/type_name/_search
{
    "query": {
        "bool": {
            "must": [],
            "should": [],
            ...
        }
    }
}
    
# 示例
POST _search
{
  "query": {
    "bool" : {
      "must" : {
        "term" : { "user" : "kimchy" }
      },
      "filter": {
        "term" : { "tag" : "tech" }
      },
      "must_not" : {
        "range" : {
          "age" : { "gte" : 10, "lte" : 20 }
        }
      },
      "should" : [
        { "term" : { "tag" : "wow" } },
        { "term" : { "tag" : "elasticsearch" } }
      ],
      "minimum_should_match" : 1
    }
  }
}

# bool中可以放置的内容
must,must_not,should,filter
  • must:属于query上下文,单个或多个条件必须都满足,参与评分
  • filter:属于filter上下文,根据条件进行过滤,不参与评分
  • should:如果查询条件组合同时存在should和query上下文,那么should中的一个或者多个条件都可以不满足,如果查询条件组合中只有should或者只有should和filter上下文,那么should中的一个或者多个条件必须满足一个,should的条件参与评分
  • must_not:属于filter上下文,单个或者多个条件必须都不满足,不参与评分,使用must_not查询出的document的分数都为0
  • minimum_should_match:使用这个参数来指定should的具体行为
    • 正数,例如3,那么should的多个条件中必须满足3个条件
    • 负数,例如-2,代表可以有2个条件不满足,其他都应该满足
    • 百分比正数:代表should条件总数的百分比个条件应该满足,例如总共10个条件,百分比为30%,那么至少3个条件应该满足,需满足条件的个数向下取整
    • 百分比负数:代表占此比例的条件可以不满足,其余的均需要满足,计算结果向下取整
    • 百分比和数字组合:3<90%,如果条件个数<=3,那么必须全部满足,否则,满足90%(向下取整)即可
    • 多个组合(空格隔开):2<-25% 9<-3,如果条件个数<=2,则必须都满足,如果条件个数为[3,9],则需要25%的条件满足,否则,只能有3个条件不满足,其余都需要满足
  • must、must_not、should、filter之间是&的关系,即这些条件都应该满足

6. 自定义排序规则

默认情况下,是按照"_score"降序排序的,使用"sort"参数来自定义排序规则

代码语言:javascript
复制
GET /company/employee/_search
{
  "query": {
    "range": {
      "age": {
        "gte": 30
      }
    }
  },
  "sort": [
    {
      "join_date": {
        "order": "desc"
      }
    }
  ]
}

GET /company/employee/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "range": {
          "age": {
            "gte": 30
          }
        }
      }
    }
  },
  "sort": [
    {
      "join_date": {
        "order": "asc"
      }
    }
  ]
}

7. DSL校验

构建好一个复杂的查询之后,可以先校验一下语句,通过返回的异常信息来修改语句,校验语法如下:

代码语言:javascript
复制
GET /test_index/test_type/_validate/query?explain
{
  "query": {
    "math": { # 这里故意把match写为了math
      "test_field": "test"
    }
  }
}

{
  "valid": false,
  "error": "org.elasticsearch.common.ParsingException: no [query] registered for [math]"
}

GET /test_index/test_type/_validate/query?explain
{
  "query": {
    "match": {
      "test_field": "test"
    }
  }
}

{
  "valid": true,
  "_shards": {
    "total": 1,
    "successful": 1,
    "failed": 0
  },
  "explanations": [
    {
      "index": "test_index",
      "valid": true,
      "explanation": "+test_field:test #(#_type:test_type)"
    }
  ]
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 多种搜索方式
    • 1.1 Query String Search:在请求URL中包括search的参数
      • 1.2 Query DSL(Domain Specified Language):查询领域专用语言
        • 1.3 查询结果元数据分析
        • 2. 词条查询(term)和全文检索(full text)
          • 2.1 准备测试数据
            • 2.2 term测试
              • 2.3 terms测试
                • 2.4 match测试
                  • 2.5 multi_match测试
                    • 2.6 match_phrase测试
                      • 2.7 match_all测试
                        • 2.8 match_phrase_prefix测试
                          • 2.9 总结
                          • 3. 范围查询
                          • 4. query上下文和filter上下文
                          • 5. 多条件组合查询
                          • 6. 自定义排序规则
                          • 7. DSL校验
                          相关产品与服务
                          Elasticsearch Service
                          腾讯云 Elasticsearch Service(ES)是云端全托管海量数据检索分析服务,拥有高性能自研内核,集成X-Pack。ES 支持通过自治索引、存算分离、集群巡检等特性轻松管理集群,也支持免运维、自动弹性、按需使用的 Serverless 模式。使用 ES 您可以高效构建信息检索、日志分析、运维监控等服务,它独特的向量检索还可助您构建基于语义、图像的AI深度应用。
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档