• ElasticSearch搜索引擎使用指南


    一、ES数据基础类型

    1、数据类型

    字符串

    主要包括: text和keyword两种类型,keyword代表精确值不会参与分词,text类型的字符串会参与分词处理

    数值

    包括: long, integer, short, byte, double, float

    布尔值

    boolean

    时间

    date

    数组

    数组类型不需要专门定义,只要插入的字段值是json数组就行

    GEO类型

    主要涉及地理信息检索、多边形区域的表达

    2、text&keyword使用注意

    text类型,支持全文搜索,因为text涉及分词,所以可以配置使用什么分词器,尤其涉及中文分词。

    实际项目中,如果不需要模糊搜索的字符类型,可以选择keyword类型,例如:手机号、email、微信的openid等等,如果选text类型,可能会出现搜出一大堆相似的数据,而且不是精确的数据。

    二、query语法

    query子句主要用于编写查询条件,类似于SQL中的where语句。

    query子句主要用于编写类似SQL的where语句,支持布尔查询(and/or)、IN、全文搜索、模糊匹配、范围查询(大于/小于)。

    其中:text类型字段支持分词,可以使用模糊查询。keyword类型只能做等值查询,不能进行分词。

    1、match类like匹配

    1.1 match匹配单个字段

    使用match实现全文搜索。类似于SQL中的like操作。

    简单使用的语法:

    1. GET /{索引名}/_search
    2. {
    3. "query": {
    4. "match": {
    5. "{FIELD}": "{TEXT}"
    6. }
    7. }
    8. }

    说明:
    {FIELD} - 就是我们需要匹配的字段名
    {TEXT} - 就是我们需要匹配的内容

    例子:

    1. GET /article/_search
    2. {
    3. "query": {
    4. "match" : {
    5. "title" : "ES教程"
    6. }
    7. }
    8. }

    article索引中,title字段匹配“ES教程”的所有文档。

    如果title字段的数据类型是text类型,搜索关键词会进行分词处理。

    等价SQL(假设"ES教程"没有进行分词):

    select * from article where title like '%ES教程%'

    1.2 multi_match多字段匹配

    例子:

    1. GET /article/_search
    2. {
    3. "query": {
    4. "multi_match": {
    5. "query": "斯柯达前轮制动器",
    6. "fields":[
    7. "doc_title",
    8. "doc_content"
    9. ]
    10. }
    11. }
    12. }

    等价SQL:

    select * from article where doc_title like '%<斯柯达前轮制动器的分词>%' or doc_content like '%<斯柯达前轮制动器的分词>%'

    因为 斯柯达前轮制动器的分词 会有很多,所以实际上也会有很多的like,而不仅仅是上面的两个like。

    1.3 multi_phrase顺序匹配

    match_phrase查询是ES中一种用于精确匹配短语的查询方式,可以确保查询字符串中的关键词按照给定的顺序在文档中连续出现。

    说明:检索词还是进行分词的,分词后的各个单词的顺序在 被检索的文中是一样的。

    例子:

    1. GET /article/_search
    2. {
    3. "query": {
    4. "match_phrase": {
    5. "doc_content": "制动器装配"
    6. }
    7. }
    8. }

    搜索结果:

    1.4 operator的布尔操作 

    指定分词匹配的布尔规则,默认情况下operator为or,即分词中有一个匹配即可。

    当operator为and时,需要文档匹配所有的分词。

    例子:

    1. GET demo_idx/_search
    2. {
    3. "query": {
    4. "match": {
    5. "content": {
    6. "query": "simple rest apis distributed nature",
    7. "operator": "and"
    8. }
    9. }
    10. }
    11. }

    1.5 结合operator、boost及match_phrase的查询

    我们希望精确匹配在搜索结果中排名较高,但也希望看到结果中相关性较低的文档,此时使用should子句来组合OR、AND和match短语查询。布尔查询中的should子句采用更好匹配的方法,因此每个子句的得分将为每个文档的最终_score做出贡献。

    1. GET demo_idx/_search
    2. {
    3. "query": {
    4. "bool": {
    5. "should": [
    6. {
    7. "match": {
    8. "content": {
    9. "query": "simple rest apis distributed nature"
    10. }
    11. }
    12. },
    13. {
    14. "match": {
    15. "content": {
    16. "query": "simple rest apis distributed nature",
    17. "operator": "and"
    18. }
    19. }
    20. },
    21. {
    22. "match_phrase": {
    23. "content": {
    24. "query": "simple rest apis distributed nature",
    25. "boost": 2
    26. }
    27. }
    28. }
    29. ]
    30. }
    31. }
    32. }

    2、term精确匹配单个字段

    使用term实现精确匹配

    如果想要类似SQL语句中的等值匹配,不需要进行分词处理,例如:订单号、手机号、时间字段,不需要分值处理,只要精确匹配。

    语法:

    1. GET /{索引名}/_search
    2. {
    3. "query": {
    4. "term": {
    5. "{FIELD}": "{VALUE}"
    6. }
    7. }
    8. }

    {FIELD} - 就是我们需要匹配的字段名
    {VALUE} - 就是我们需要匹配的内容,除了TEXT类型字段以外的任意类型

    例子:

    1. GET /order_v2/_search
    2. {
    3. "query": {
    4. "term": {
    5. "order_no": "202003131209120999"
    6. }
    7. }
    8. }

    搜索订单号order_no = "202003131209120999"的文档。

    类似SQL语句:

    select * from order_v2 where order_no = "202003131209120999"

    3、terms实现SQL的in语句

    如果我们要实现SQL中的in语句,一个字段包含给定数组中的任意一个值就匹配。

    语法:

    1. GET /order_v2/_search
    2. {
    3. "query": {
    4. "terms": {
    5. "{FIELD}": [
    6. "{VALUE1}",
    7. "{VALUE2}"
    8. ]
    9. }
    10. }
    11. }

    说明:

    {FIELD} - 就是我们需要匹配的字段名
    {VALUE1}, {VALUE2} … {VALUE N} - 就是我们需要匹配的内容,除了TEXT类型字段以外的任意类型。

    例子:

    1. GET /order_v2/_search
    2. {
    3. "query": {
    4. "terms": {
    5. "shop_id": [123,100,300]
    6. }
    7. }
    8. }

    搜索order_v2索引中,shop_id字段,只要包含[123,100,300]其中一个值,就算匹配。

    类似SQL语句:

    select * from order_v2 where shop_id in (123,100,300)

    4、range范围查询

    通过range实现范围查询,类似SQL语句中的>, >=, <, <=表达式。

    语法:

    1. GET /{索引名}/_search
    2. {
    3. "query": {
    4. "range": {
    5. "{FIELD}": {
    6. "gte": 10,
    7. "lte": 20
    8. }
    9. }
    10. }
    11. }

    参数说明:

    {FIELD} - 字段名

    gte范围参数 - 等价于>=

    lte范围参数 - 等价于 <=

    范围参数可以只写一个,例如:仅保留 “gte”: 10, 则代表 FIELD字段 >= 10

    范围参数如下:

    1. gt - 大于 ( >
    2. gte - 大于且等于 ( >=
    3. lt - 小于 ( <
    4. lte - 小于且等于 ( <=

    例子:

    1. GET /order_v2/_search
    2. {
    3. "query": {
    4. "range": {
    5. "shop_id": {
    6. "gte": 10,
    7. "lte": 200
    8. }
    9. }
    10. }
    11. }

    查询order_v2索引中,shop_id >= 10 且 shop_id <= 200的文档。类似SQL:

    select * from order_v2 where shop_id >= 10 and shop_id <= 200

    5、bool组合查询

    前面的例子都是设置单个字段的查询条件,如果想要编写类似SQL的Where语句组合多个字段的查询条件,可以使用bool语句。

    5.1 bool查询基本语法结构

    语法:

    1. GET /{索引名}/_search
    2. {
    3. "query": {
    4. "bool": { // bool查询
    5. "must": [], // must条件,类似SQL中的and, 代表必须匹配条件
    6. "must_not": [], // must_not条件,跟must相反,必须不匹配条件
    7. "should": [] // should条件,类似SQLor, 代表匹配其中一个条件
    8. }
    9. }
    10. }

    must、must_not和should条件的参数都是一个数组,意味着他们都支持设置多个条件。

    同时,前面介绍的单个字段的匹配语句,都可以用在bool查询语句中进行组合。

    5.2 must条件

    类似SQL的and,代表必须匹配的条件。

    语法:

    1. GET /{索引名}/_search
    2. {
    3. "query": {
    4. "bool": {
    5. "must": [
    6. {匹配条件1},
    7. {匹配条件2},
    8. ...可以有N个匹配条件...
    9. ]
    10. }
    11. }
    12. }

    例子:

    1. GET /order_v2/_search
    2. {
    3. "query": {
    4. "bool": {
    5. "must": [
    6. {
    7. "term": {
    8. "order_no": "202003131209120999"
    9. }
    10. },
    11. {
    12. "term": {
    13. "shop_id": 123
    14. }
    15. }
    16. ]
    17. }
    18. }
    19. }

    这里的Must条件,使用了term精确匹配,等价SQL:

    select * from order_v2 where order_no="202003131209120999" and shop_id=123

    5.3 must_not条件

    跟must的作用相反,语法类似。

    5.4 should条件

    类似SQL中的 or, 只要匹配其中一个条件即可。

    语法:

    1. GET /{索引名}/_search
    2. {
    3. "query": {
    4. "bool": {
    5. "should": [
    6. {匹配条件1},
    7. {匹配条件2},
    8. …可以有N个匹配条件…
    9. ]
    10. }
    11. }
    12. }

    例子:

    1. GET /order_v2/_search
    2. {
    3. "query": {
    4. "bool": {
    5. "should": [
    6. {
    7. "term": {
    8. "order_no": "202003131209120999"
    9. }
    10. },
    11. {
    12. "term": {
    13. "order_no": "22222222222222222"
    14. }
    15. }
    16. ]
    17. }
    18. }
    19. }

    等价SQL:

    select * from order_v2 where order_no="202003131209120999" or order_no="22222222222222222"

    5.5 bool综合例子

    1. GET /order_v2/_search
    2. {
    3. "query": {
    4. "bool": {
    5. "should": [
    6. {
    7. "bool": {
    8. "must": [
    9. {
    10. "term": {
    11. "order_no": "2020031312091209991"
    12. }
    13. },
    14. {
    15. "range": {
    16. "shop_id": {
    17. "gte": 10,
    18. "lte": 200
    19. }
    20. }
    21. }
    22. ]
    23. }
    24. },
    25. {
    26. "terms": {
    27. "tag": [
    28. 1,
    29. 2,
    30. 3,
    31. 4,
    32. 5,
    33. 12
    34. ]
    35. }
    36. }
    37. ]
    38. }
    39. }
    40. }

    等价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)
    

    6、wildcard通配符查询

    wildcard 关键字: 通配符查询 ? 用来匹配一个任意字符 * 用来匹配多个任意字符。

    例子:

    1. GET /xizi/emp/_search
    2. {
    3. "query": {
    4. "wildcard": {
    5. "name": {
    6. "value": "xi*"
    7. }
    8. }
    9. }
    10. }

    7、fuzzy模糊查询

    fuzzy 模糊查询,最大模糊错误必须在0-2之间  

    搜索关键词长度为 2 不允许存在模糊 0

     搜索关键词长度为3-5 允许一次模糊 0 1  

    搜索关键词长度大于5 允许最大2模糊

    例子:

    1. GET /xizi/emp/_search
    2. {
    3. "query": {
    4. "fuzzy": {
    5. "name":"xizi"
    6. }
    7. }
    8. }

    8、额外限制条件

    8.1 _source指定返回字段

    例子1:

    1. get lib3/user/_search
    2. {
    3. "_source":["name","age"],
    4. "query":{
    5. "match": {
    6. "interests": "changge"
    7. }
    8. }

    结果只返回索引中name和age字段信息

    例子2:

    1. get lib3/user/_search
    2. {
    3. "query":{
    4. "match_all": {}
    5. },
    6. "_source":{
    7. "includes": "addr*",
    8. "excludes": ["name","bir*"]
    9. }
    10. }

    显示要的字段、去除不需要的字段、可以使用通配符*。

    8.2 boost查询的权重

    boost值控制每个查询子句的相对权重,该值默认为1。

    boost参数被用来增加一个子句的相对权重(当boost大于1时),或者减小相对权重(当boost介于0到1时),但是增加或者减小不是线性的。换言之,boost设为2并不会让最终的_score加倍。

    例子:

    1. GET/_search{
    2. "query": {
    3. "bool": {
    4. "must": {
    5. "match": {
    6. "content": {
    7. "query": "full text search",
    8. "operator": "and"
    9. }
    10. }
    11. },
    12. "should": [{
    13. "match": {
    14. "content": {
    15. "query": "Elasticsearch",
    16. "boost": 3
    17. }
    18. }
    19. },
    20. {
    21. "match": {
    22. "content": {
    23. "query": "Lucene",
    24. "boost": 2
    25. }
    26. }
    27. }]
    28. }
    29. }
    30. }

    8.3 min_similarity设置匹配的最小相似度

    8.4 highlight高亮搜索结果

    例子:

    1. get data_info/_search
    2. {
    3. "_source":["doc_title","doc_content"],
    4. "query": {
    5. "match": {
    6. "doc_content": "斯柯达前轮制动器"
    7. }
    8. },
    9. "highlight":{
    10. "fields":{
    11. "doc_content":{}
    12. }
    13. }
    14. }

    返回结果:

    8.5 size指定返回条数

    ES默认返回10条结果。

    例子:

    1. get data_info/_search
    2. {
    3. "query": {
    4. "match": {
    5. "doc_content": "斯柯达前轮制动器"
    6. }
    7. },
    8. "size": 2
    9. }

    结果中只有2条信息。

    8.6 from分页查询

    from 关键字: 用来指定起始返回位置,和size关键字连用可实现分页效果。

    例子:

    1. get data_info/_search
    2. {
    3. "query": {
    4. "match": {
    5. "doc_content": "斯柯达前轮制动器"
    6. }
    7. },
    8. "size": 2,
    9. "from": 3
    10. }

    8.7 sort指定字段排序

    使用该属性会让得分失效

    例子:

    1. GET /db_idx4/_search
    2. {
    3. "query":{
    4. "match_all":{
    5. }
    6. },
    7. "sort":[
    8. {
    9. "age":"desc"
    10. }
    11. ]
    12. }

    8.8 explain查看分数计算详情

    ES提供了一个解释性API和一个解释性查询参数以了解如何计算分数。

    例子:

    1. GET /db_idx4/_search
    2. {
    3. "explain": true,
    4. "query": {
    5. "match_phrase": {
    6. "doc_content": "制动器装配"
    7. }
    8. }
    9. }

    结果示例:

    三、全文搜索

    1、概念

    平时我们使用SQL like语句搜索一些文本、字符串是否包含指定的关键词,如果两篇文章都包含我们的关键词,那么具体哪篇文章内容的相关度更高?这个SQL的like语句是做不到的,更别说like语句的性能问题了。

    ES通过分词、相关度计算可以解决这个问题,ES内置了一些相关度算法,大致上意思是:如果一个关键词在一篇文章出现的频率高,并且在其他文章中出现少,那说明这个关键词与这篇文章的相关度很高。

    ES对于text类型的字段,在插入数据的时候,会进行分词处理,然后根据分词的结果索引文档,当我们搜索text类型字段的时候,也会先对搜索关键词进行分词处理、然后根据分词的结果去搜索。

    2、文档评分计算

    2.1 默认评分影响因素

    ES使用的默认评分算法是BM25,决定文档得分的3个主要因素:

    • 字词频率(TF):搜索字词在我们正在搜索的文档中的字段中出现的次数越多,则该文档越相关
    • 反向文档频率(IDF):在我们要搜索的字段中包含搜索词的文档越多,该词的重要性就越低
    • 字段长度:如果文档在非常短的字段(即,只有几个单词)中包含搜索词,则比文档在较长的字段(即,包含很多单词)中包含搜索词更相关

    2.2 使用function_score和script_score定制搜索结果分数

    function_score和script_score是很耗资源的,所以实际使用时只需要计算一组经过过滤的文档的分数。

    script_score定制的例子:

    1. GET best_games/_search
    2. {
    3. "_source": [
    4. "name",
    5. "critic_score",
    6. "user_score"
    7. ],
    8. "query": {
    9. "script_score": {
    10. "query": {
    11. "match": {
    12. "name": "Final Fantasy"
    13. }
    14. },
    15. "script": {
    16. "source": "_score * (doc['user_score'].value*10+doc['critic_score'].value)/2/100"
    17. }
    18. }
    19. }
    20. }

    具体细节参考:Elasticsearch:使用 function_score 及 script_score 定制搜索结果的分数-CSDN博客

     

    3、分词效果测试

    语法:

    1. GET /_analyze
    2. {
    3. "text": "需要分词的内容",
    4. "analyzer": "分词器"
    5. }

    例子:

    1. GET http://xx.elasticsearch.aliyuncs.com:9200/_analyze
    2. {
    3. "text":"上海大学",
    4. "analyzer": "standard"
    5. }

    使用standard分词器,对"上海大学"进行分词,下面是输出结果:

    1. {
    2. "tokens": [
    3. {
    4. "token": "上",
    5. "start_offset": 0,
    6. "end_offset": 1,
    7. "type": "",
    8. "position": 0
    9. },
    10. {
    11. "token": "海",
    12. "start_offset": 1,
    13. "end_offset": 2,
    14. "type": "",
    15. "position": 1
    16. },
    17. {
    18. "token": "大",
    19. "start_offset": 2,
    20. "end_offset": 3,
    21. "type": "",
    22. "position": 2
    23. },
    24. {
    25. "token": "学",
    26. "start_offset": 3,
    27. "end_offset": 4,
    28. "type": "",
    29. "position": 3
    30. }
    31. ]
    32. }

    token就是分解出来的关键词。

    四、难点剖析

    1、filter与must的区别

    同样是按条件匹配,filter不统计相关度,must统计相关度。就是filter不计算score分数值,而must是计算的。所以must比filter计算更复杂、更耗时。

    具体参考:Elasticsearch Query: filter与must的区别_elasticsearch must 和filter的区别-CSDN博客

  • 相关阅读:
    APIView单一资源的查看更新删除
    基于GPIO子系统编写LED驱动
    实现upt下客户端用tftp文件传输协议编写客户端发送下载文件
    elementplus如何实现dialog遮罩层外的元素可以被操作点击
    IOS17正式版今日发布
    机器学习笔记之线性分类——线性判别分析(二)模型参数求解过程
    LeetCode50天刷题计划第二季(Day 27 — 寻找旋转排序数组中的最小值(9.50- 11.20)
    Citus 11 for Postgres 完全开源,可从任何节点查询(Citus 官方博客)
    Stable Diffusion 模型下载:Comic Babes(漫画宝贝)
    15:00面试,15:08就出来了,问的问题有点变态。。。
  • 原文地址:https://blog.csdn.net/benben044/article/details/136394190