首页 > 解决方案 > ElasticSearch 多个 AND/OR 查询

问题描述

我有一个如下所示的架构 -

{
    "errorCode": "e015",
    "errorDescription": "Description e015",
    "storeId": "71102",
    "businessFunction": "PriceFeedIntegration",
    "createdDate": "2021-02-20T09:17:04.004",
    "readBy": [
        {
            "userId": "scha3055"
        },
    {
            "userId": "abcd1234"
        }

    ]
}

我正在尝试搜索具有如下日期范围的“errorCode”、“storeId”、“businessFunction”的组合 -

{
    "query": {
        "bool": {
            "must": [
                {
                    "terms": {
                        "errorCode": [
                            "e015",
                            "e020",
                            "e022"
                        ]
                    }
                },
                {
                    "terms": {
                        "storeId": [
                            "71102",
                            "71103"
                        ]
                    }
                },
                
                {
                    "range": {
                        "createdDate": {
                            "gte": "2021-02-16T09:17:04.000",
                            "lte": "2021-02-22T00:00:00.005"
                        }
                    }
                }
            ]
        }
    }
}

但是,当我使用“businessFunction”添加另一个条件时,查询不起作用。

{
    "query": {
        "bool": {
            "must": [
                {
                    "terms": {
                        "errorCode": [
                            "e015",
                            "e020",
                            "e022"
                        ]
                    }
                },
                {
                    "terms": {
                        "storeId": [
                            "71102",
                            "71103"
                        ]
                    }
                },
                {
                    "terms": {
                        "errorDescription": [
                            "Description e020",
                            "71103"
                        ]
                    }
                },
                {
                    "range": {
                        "createdDate": {
                            "gte": "2021-02-16T09:17:04.000",
                            "lte": "2021-02-22T00:00:00.005"
                        }
                    }
                }
            ]
        }
    }
}

我在查询中遗漏了什么?当我添加第三个“术语” cndition 时,查询不起作用。请建议或让我知道任何替代方式。

标签: elasticsearch

解决方案


在您的示例中,您正在搜索“Description e020”,但在您的示例中,您存储了“Description e015 ”。

简短的回答,我希望这适合你:

"Description e015" 将被索引为两个术语 ["description","e015"]。

使用match_phrase而不是术语

 ...
 {
          "match_phrase": {
            "errorDescription": "Description e015"
          }
},
{
          "range": {
            "createdDate": {
              "gte": "2021-02-16T09:17:04.000",
              "lte": "2021-02-22T00:00:00.005"
            }
          }
}
....

在不知道您的映射的情况下,我认为您的 errorDescription 字段已被分析。

不推荐其他选项:如果您的字段已分析并且您需要完全匹配,请在 errorDescription.keyword 中搜索

{
  "terms": {
    "errorDescription.keyword": [
      "Description e015"              
    ]
  }
}

更新

长答案:

正如我之前提到的,您的字段值已被分析,然后从“PriceFeedIntegration2”转换为 pricefeedintegration2。

2 个选项

  • 按您的 field.keyword 又名 businessFunction.keyword 搜索
  • 将您的字段映射更改为未分析。然后,您可以使用术语获得预期的结果。

选项1

这是一种简单的方法,如果您从未在该字段上运行全文搜索,最好不要将其用作默认值。如果没关系,就用这个选项,是最简单的。

检查您的 businessFunction.keyword 字段(如果您不指定映射,则默认创建)

索引数据而不映射到my000001索引

curl -X "POST"  "http://localhost:9200/my000001/_doc" \
-H "Content-type: application/json" \
-d $'
{  
     "errorCode": "e015",
    "errorDescription": "Description e015",
    "storeId": "71102",
    "businessFunction": "PriceFeedIntegration",
    "createdDate": "2021-02-20T09:17:04.004"
   
}'

查看

curl -X "GET" "localhost:9200/my000001/_analyze" \
-H "Content-type: application/json" \
-d $'{
  "field": "businessFunction.keyword",
  "text": "PriceFeedIntegration"
}'

结果:

{
  "tokens": [
    {
      "token": "PriceFeedIntegration",
      "start_offset": 0,
      "end_offset": 20,
      "type": "word",
      "position": 0
    }
  ]
}

使用 businessFunction.keyword 获取结果

curl -X "GET" "localhost:9200/my000001/_search" \
-H "Content-type: application/json" \
-d $'{
  "query": {

    "bool": {
      
      "must": [
        {
          "terms": {
            "errorCode": [
              "e015",
              "e020",
              "e022"
            ]
          }
        },
        {
          "terms": {
            "storeId": [
              "71102",
              "71103"
            ]
          }
        },
        {
          "terms": {
            "businessFunction.keyword": [
              "PriceFeedIntegration2",
              "PriceFeedIntegration"
            ]
          }
        },
        {
          "range": {
            "createdDate": {
              "gte": "2021-02-16T09:17:04.000",
              "lte": "2021-02-22T00:00:00.005"
            }
          }
        }
      ]
    }
  }
}' | jq

为什么不推荐作为默认选项?

“默认的动态字符串映射会将字符串字段作为文本和关键字进行索引。如果您只需要其中一个,这将是一种浪费。”

https://www.elastic.co/guide/en/elasticsearch/reference/current/tune-for-disk-usage.html

选项 2

my000001索引上运行

curl -X "GET" "localhost:9200/my000001/_analyze" \
-H "Content-type: application/json" \
-d $'{
  "field": "businessFunction",
  "text": "PriceFeedIntegration"
}'

您可以看到,您的字段值已被分析(标记化、小写和其他修改,具体取决于分析器和提供的值)结果:

{
  "tokens": [
    {
      "token": "pricefeedintegration",
      "start_offset": 0,
      "end_offset": 20,
      "type": "<ALPHANUM>",
      "position": 0
    }
  ]
}

这就是您的搜索不返回结果的原因。

“PriceFeedIntegration”与“pricefeedintegration”不匹配

“问题不在于术语查询;而在于数据的索引方式。”

您的 businessFunction 字段值已被分析。

如果您需要按精确值查找(搜索/过滤),则可能需要将“businessFunction”字段映射更改为 not_analyzed。

更改您的映射需要删除您的索引并再次创建提供所需的映射。

如果您尝试更改现有索引的映射,您将收到“resource_already_exists_exception”错误。

以下是解决问题所需了解的背景: https ://www.elastic.co/guide/en/elasticsearch/guide/master/_finding_exact_values.html#_finding_exact_values

在新的my000005索引上创建映射

curl -X "PUT" "localhost:9200/my000005" \
-H "Content-type: application/json" \
-d $'{

    "mappings" : {      
            "properties" : {
                "businessFunction" : {
                    "type" : "keyword"                    
                },
                "errorDescription" : {
                    "type" : "text"                    
                },
                 "errorCode" : {
                    "type" : "keyword"                    
                },
                 "createdDate" : {
                    "type" : "date"                    
                },
                "storeId": {
                    "type" : "keyword"                    
                }
            }
        }
}'

索引数据

curl -X "POST"  "http://localhost:9200/my000005/_doc" \
-H "Content-type: application/json" \
-d $'
{  
     "errorCode": "e015",
    "errorDescription": "Description e015",
    "storeId": "71102",
    "businessFunction": "PriceFeedIntegration",
    "createdDate": "2021-02-20T09:17:04.004"
   
}'

使用术语 businessFunction 获得您期望的结果

curl -X "GET" "localhost:9200/my000005/_search" \
-H "Content-type: application/json" \
-d $'{
  "query": {

    "bool": {
      
      "must": [
        {
          "terms": {
            "errorCode": [
              "e015",
              "e020",
              "e022"
            ]
          }
        },
        {
          "terms": {
            "storeId": [
              "71102",
              "71103"
            ]
          }
        },
        {
          "terms": {
            "businessFunction": [
              "PriceFeedIntegration2",
              "PriceFeedIntegration"
            ]
          }
        },
        {
          "range": {
            "createdDate": {
              "gte": "2021-02-16T09:17:04.000",
              "lte": "2021-02-22T00:00:00.005"
            }
          }
        }
      ]
    }
  }
}' | jq

这个答案是基于我认为你的映射和你的需求。

将来分享你的映射和你的 ES 版本,以便从社区中得到更好的答案。

curl -X "GET" "localhost:9200/yourindex/_mappings"

请阅读此https://www.elastic.co/guide/en/elasticsearch/guide/master/_finding_exact_values.html#_finding_exact_values 和此https://www.elastic.co/blog/strings-are-dead-long-现场弦乐


推荐阅读