8. 常见ES结构化搜索

mapping说明

mapping结构如下

1
2
3
4
5
6
7
8
9
"某字段" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}

term查询注意事项

在Elasticsearch中,term查询用于对精确值进行匹配。对于字段类型的考虑,有两个关键点需要注意:

  1. Text vs Keyword: 在Elasticsearch中,text类型的字段通常用于全文搜索,这些字段在索引时会被分词。而keyword类型的字段用于精确值匹配,不会被分词。

  2. 使用keyword字段进行term查询: 虽然text类型的字段理论上也可以用于term查询,但通常不推荐这样做,因为text字段上的term查询会对字段的每个分词进行匹配,这通常不是预期的行为。相反,keyword类型的字段非常适合用于term查询,因为它们不会被分词。

如下,某字段字段是一个text类型的字段,但它还定义了一个名为keyword的子字段。这意味着您可以使用某字段.keyword来执行term查询,以精确匹配特定的值。

因此,要对某字段字段进行term查询,您应该使用它的keyword子字段,如下所示:

1
2
3
4
5
6
7
8
9
{
"query": {
"term": {
"某字段.keyword": {
"value": "您想查询的值"
}
}
}
}

在这个查询中,某字段.keyword将确保对该字段的精确值进行匹配。

如果在query.term中直接使用text类型的字段(比如某字段)而不是它的.keyword子字段,可能会导致查询不按预期工作。原因如下:

  1. 分词处理text类型的字段在索引时会被分词。这意味着文本会被拆分成较小的单元(通常是单词)。当使用term查询text字段时,Elasticsearch会尝试将您提供的精确值与这些分词后的单元进行匹配。

  2. 查询结果不准确:因为text字段被分词,所以term查询可能会返回不符合预期的结果。例如,如果您试图精确匹配一个短语或一个包含多个词的字符串,查询可能会失败,因为整个短语或字符串作为一个整体并不存在于分词后的索引中。

  3. 效率问题:对text字段使用term查询通常也不是效率最高的做法。term查询更适合用于未分词的keyword字段。

综上所述,当需要进行精确匹配时,最好是使用字段的.keyword子字段进行term查询。如果直接对text字段使用term查询,可能不会得到正确或期望的结果。

ignore_above说明

在Elasticsearch中,ignore_above 是一个设置项,用于指定一个字符长度限制。当字段的类型被设置为 keyword 时,这个设置非常有用。它的主要作用如下:

  1. 字符长度限制ignore_above 设置一个最大字符长度。如果字段的值超过这个长度,Elasticsearch 将不会对该字段值进行索引。

  2. 避免昂贵的操作:这个设置有助于避免对非常长的文本进行索引操作,这些操作可能是资源密集型的并且很少用于搜索。

  3. 影响索引和搜索:如果一个字段的值长度超过了 ignore_above 设置的长度,那么这个值不会被索引,也就无法通过搜索查询到。但这个值仍然会被存储在文档中,并且可以在返回文档时查看。

  4. 用途示例:比如,如果你有一个字段通常包含短的编码或标识符,但偶尔会有非常长的值,你可能不想索引这些长值。在这种情况下,设置 ignore_above 可以保证只有短的、可能用于搜索的值被索引。

在字段设置中:

1
2
3
4
5
6
"某字段" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}

这意味着对于 某字段 字段的 keyword 子字段,任何超过 256 个字符的值都不会被索引。这有助于优化索引的性能,特别是当字段值可能非常长时。但请注意,这不会影响字段值的存储,在_source中返回的文档仍然会包含原始的未切割值。

must和filter区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"query": {
"bool": {
"must": {
"match_all": {}
},
"filter": {
"term": {
"id": "123"
}
}
}
}
}

在Elasticsearch的查询中,filterbool 查询的一部分,用于定义一个或多个过滤条件。filter 上的条件必须被满足,但它们不会影响搜索结果的相关性得分(scoring)。下面解释一下您提到的查询中的filter的作用和是否必需:

  1. 作用filter内的条件用于过滤结果集,以确保只返回满足这些条件的文档。在您的查询中,filter里的term查询是用来精确匹配字段id的值为123的文档。

  2. 是否必需filter不是必需的,它的使用取决于您的查询需求。如果您只需要返回所有文档而不关心特定条件,那么可以省略filter。但如果您需要根据特定的条件来限制返回的文档,那么filter就非常有用。

  3. must的区别:在bool查询中,mustfilter都用于指定必须满足的条件,但它们的关键区别在于:

    • must:用于包含那些必须匹配的条件,这些条件会影响文档的相关性得分。
    • filter:用于包含那些必须匹配的条件,但这些条件不影响相关性得分。filter通常用于范围查询、存在查询等,其中文档的得分不重要。

在您的查询示例中,match_all配合filter的使用意味着查询会返回所有文档,但只有那些id字段值为123的文档会被包含在结果中。如果您不需要基于特定条件过滤文档,那么您可以省略filter部分。

如何查看es的分词效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
POST http://IP:9200/索引名称/_analyze
Content-Type: application/json
{
"field": "字段名称",
"text": "示例"
}
返回:
{
"tokens": [
{
"token": "示",
"start_offset": 0,
"end_offset": 1,
"type": "<IDEOGRAPHIC>",
"position": 0
},
{
"token": "例",
"start_offset": 1,
"end_offset": 2,
"type": "<IDEOGRAPHIC>",
"position": 1
}
]
}

term精确查询

如果字段不是text,是基础类型,则不用加.keyword

1
2
3
4
5
6
7
8
9
POST http://IP:9200/索引名称/_search
Content-Type: application/json
{
"query": {
"term": {
"字段名称.keyword": "内容"
}
}
}

term组合查询

简单组合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
POST http://IP:9200/索引名称/_search
Content-Type: application/json
{
"query": {
"bool": {
"should": [
{
"term": {
"字段.keyword": "2023-10-25 20:07:28.0"
}
}
],
"must_not": [
{
"term": {
"字段.keyword": "测试"
}
}
]
}
}
}

嵌套组合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
POST http://IP:9200/索引名称/_search
Content-Type: application/json
{
"query": {
"bool": {
"should": [
{
"term": {
"字段.keyword": "2023-10-25 20:07:28.0"
}
}
],
"must": [
{
"bool": {
"must": [
{
"term": {
"id.keyword": "123"
}
}
]
}
}
],
"must_not": [
{
"term": {
"字段.keyword": "测试"
}
}
]
}
}
}

terms多个值查询

注意1: key是terms而不是term,数组是中or的关系,类似mysql的in查询
注意2: term和terms的查询对象如果是array,则是【原始数据数组】包含【查询条件内容】的关系

1
2
3
4
5
6
7
8
9
POST http://IP:9200/索引名称/_search
Content-Type: application/json
{
"query": {
"terms": {
"id.keyword": ["136575", "136079111"]
}
}
}

范围查询

1
2
3
4
5
6
7
8
9
10
11
12
POST http://IP:9200/索引名称/_search
Content-Type: application/json
{
"query": {
"range": {
"id.keyword": {
"gt": "123",
"lt": "456"
}
}
}
}

字段存在/非null查询

1
2
3
4
5
6
7
8
9
POST http://IP:9200/索引名称/_search
Content-Type: application/json
{
"query": {
"exists": {
"field": "字段名称"
}
}
}

字段不存在/null查询

老版本的missing已经取消,需要使用bool的must_not结合exists使用

1
2
3
4
5
6
7
8
9
10
11
12
13
POST http://IP:9200/索引名称/_search
Content-Type: application/json
{
"query": {
"bool": {
"must_not": {
"exists": {
"field": "字段名称"
}
}
}
}
}