elasticSearch(四):还在无脑使用match、term么?

435 阅读6分钟

查询

介绍

检索是es最核心的功能,它能够快速、精准的从海量数据中检索出用户最想要的数据。而在es中有很多查询关键词,如:match、term、math_pharse等,它们应用在各种检索场景下,使用错了关键词会导致准确性、查询速度大打折扣。

检索分类

image.png

精确匹配

精确匹配是es中根据确切的值查询文档的方式;精确匹配不对文档进行分词处理,它是将整个文档当作一个完整的词条,查询的关键词必须与文档中的词一模一样,才会被查询回来。它的目的主要应用于结构化数据,例如:主键、标签等内容。

全文检索

全文检索es中一种对文档内容进行深入分析和处理的方式,以便查询到与之有关的文档。它通常考虑词汇的语义关联等,并根据文档与查询关键字的相关程度来进行评分。它主要根据文档的分词器有关,分词器会对文档进行深度处理,把文档拆分成若干个词汇。全文检索主要应用于非结构化文本数据,例如:文档、评价等。

组合索引

组合查询是将多个查询条件组合在一起的检索方式。用户可以根据多个因素来定位相关的文档,从而实现较为复杂的查询。

示例

在平时工作中最常见的就是精确匹配、全文检索、组合这三种;下面会挑一些常用的关键词详细介绍。

数据准备:

PUT test_index
{
  "mappings": {
    "properties": {
      "age": {
        "type": "long"
      },
      "brith": {
        "type": "date",
        "format": "[yyyy-MM-dd HH:mm:ss]"
      },
      "city": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      },
      "pinyin": {
        "type": "text",
        "analyzer": "english"
      },
      "tags": {
        "type": "keyword"
      },
      "title": {
        "type": "text"
      }
    }
  }
}
POST test_index/_doc
{
  "title":"德玛西亚",
  "brith":"2024-07-20 10:00:00",
  "city":"德玛西亚-地点1",
  "pinyin":"de ma xi ya"
}
POST test_index/_doc
{
  "title":"德玛皇子",
  "brith":"2024-07-20 10:00:00",
  "city":"德玛西亚-地点2",
  "pinyin":"de ma huang zi"
}
POST test_index/_doc
{
  "title":"卡特琳娜",
  "brith":"2024-07-20 10:00:00",
  "tags":["刺客","法师"],
  "city":"诺克萨斯-地点1",
  "age":1,
  "pinyin":"ka te lin na"
}

POST test_index/_doc
{
  "title":"诺克萨斯",
  "brith":"2024-08-20 10:00:00",
  "tags":"展示",
  "city":"诺克萨斯-地点2",
  "age":3,
  "pinyin":"nuo ke sa si"
}

查看它的分词:

GET test_index/_analyze
{
  "text":"德玛西亚"
}
------------- 结果-------------
{
  "tokens" : [
    {
      "token" : "德",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "<IDEOGRAPHIC>",
      "position" : 0
    },
    {
      "token" : "玛",
      "start_offset" : 1,
      "end_offset" : 2,
      "type" : "<IDEOGRAPHIC>",
      "position" : 1
    },
    {
      "token" : "西",
      "start_offset" : 2,
      "end_offset" : 3,
      "type" : "<IDEOGRAPHIC>",
      "position" : 2
    },
    {
      "token" : "亚",
      "start_offset" : 3,
      "end_offset" : 4,
      "type" : "<IDEOGRAPHIC>",
      "position" : 3
    }
  ]
}

term
POST test_index/_search
{
  "query": {
    "term": {
      "title": {
        "value": "德玛西亚"
      }
    }
  }
}

POST test_index/_search
{
  "query": {
    "term": {
      "title": {
        "value": "德"
      }
    }
  }
}

第一个命令的结果是空,因为分词后没有“俄罗斯”这个词语,没办法完全匹配,如果把title的属性只设置为keyword,则不会对“德玛西亚”进行分词就可以匹配到。第二个命令会返回“俄罗斯与乌克兰”这条数据因为分词后有“俄”这个词。

terms

terms主要应用于多个值的精确匹配场景,它允许用户在单个查询中指定多个值来进行精确的匹配。例如:

POST test_index/_search
{
  "query": {
    "terms": {
      "title": [
        "德"
      ]
    }
  }
}
range

它是一种范围检索,允许用户查询一段范围内容的数据。它支持多种比较操作符:gt、gte、lt、lte等。示例:

POST test_index/_search
{
  "query": {
    "range": {
      "brith": {
        "gte": "2024-07-19 10:00:00",
        "lte": "2024-07-21 09:00:00"
      }
    }
  }
}
exists

它用于筛选索引中具有特定字段值的文档。它适用于检查文档是否存在某个字段,或者该字段是否包含非空值。示例:

POST test_index/_search
{
  "query": {
    "exists": {
      "field": "tags"
    }
  }
}
wildcard

wildcard支持通配符匹配,它允许在检索时使用通配符边大师来匹配文档的字段值。
* :表示0个或者多个字符,可用于匹配人意长度的字符串。
? :表示一个字符,用于匹配任意单个字符。
这种查询会匹配索引中的全部文档,实际开发中慎重使用。

POST test_index/_search
{
  "query": {
    "wildcard": {
      "tags": {
        "value": "?客*"
      }
    }
  }
}
prefix

前缀索引,它允许根据指定前缀查询文档的字段值,它适合查询以特定字符开头的字段。例如:

POST test_index/_search
{
  "query": {
    "prefix": {
      "city.keyword": {
        "value": "诺克萨斯"
      }
    }
  }
}
term_set

它是es中功能比较强大的检索类型;主要解决多值字段的文档匹配问题,在处理具有多个属性的复杂数据时非常有用。它的核心功能在于匹配一定数量给定词项的文档,其中匹配的数量可以是固定值,也可以是动态值。示例:查询给定标签,并且每年至少学会一个标签的英雄。

POST test_index/_search
{
  "query": {
    "terms_set":{
      "tags":{ -- 通常匹配数组或集合
        "terms":["刺客","展示"], 
        "minimum_should_match_field": "age" -- 给定一个词项,例如年龄。
      }
    }
  }
}
fuzzy

平时在搜索的时候难免会有打错字的时候,此时fuzzy就派上了用场。如:

POST test_index/_search
{
  "query": {
    "fuzzy": {
      "pinyin": {
        "value": "maa"
      }
    }
  }
}
match全文检索

match检索适合应用于高召回率和结果精确要求比较低的场景;它的本质上由bool检索和term检索相结合构成的,这意味着在确保较高召回率的前提下,它会牺牲一定的精确度和性能来满足各种查询需求。 当使用match对一个值进行查询时,会先对该值进行分词,分词后再以bool组成term进行查询。例:

POST test_index/_search
{
  "query": {
    "match": {
      "title": "德玛西亚"
    }
  }
}

此时会召唤回来两条,"德玛西亚"因为分数更高会在最前面,“德玛皇子”匹配度较低排在后面。

match_phrase

它适用于注重精确度的召回场景,与match不同,它更适合成为短语匹配查询。因为它要求查询的词条顺序和文档中的词条顺序保持一致,所以它的精确度会更高。例:

POST test_index/_search
{
  "query": {
    "match_phrase": {
      "title": "玛皇"
    }
  }
}

当使用match_phrase时只能召回回来"德玛皇子",而使用match时可以把两个都召回回来。

multi_match

它适用于多个字段上支持match的场景,由于该方法同时检索多个字段所以性能上会比单个检索更快。例:

POST test_index/_search
{
  "query": {
    "multi_match": {
      "query": "诺克萨斯",
      "fields": ["title" ,"city"]
    }
  }
}
bool

bool组合检索是一种功能强大的查询方式,当需要同时满足多个条件时可以采用bool关键词。它主要包括四种子查询:

  1. must:查询结果必须满足指定条件
  2. must_not:查询条件必须不满足指定条件。
  3. filter:过滤条件;使用filter时会缓存数据提高查询性能。
  4. should:查询时满足部分条件,由minimum_should_match参数控制。
POST test_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "prefix": {
            "city.keyword": {
              "value": "诺克萨斯"
            }
          }
        }
      ],
      "must_not": [
        {
          "term": {
            "tags": {
              "value": "刺客"
            }
          }
        }
      ]
    }
  }
}