在 elasticsearch 中使用非嵌套映射过滤聚合键

Filter aggregation keys with non nested mapping in elasticsearch

我有以下映射:

{
  "Country": {
    "properties": {
      "State": {
        "properties": {
          "Name": {
            "type": "text",
            "fields": {
              "raw": {
                "type": "keyword"
              }
            }
          },
          "Code": {
            "type": "text",
            "fields": {
              "raw": {
                "type": "keyword"
              }
            }
          },
          "Lang": {
            "type": "text",
            "fields": {
              "raw": {
                "type": "keyword"
              }
            }
          }
        }
      }
    }
  }
}

这是示例文档:

{
  "Country": {
    "State": [
      {
        "Name": "California",
        "Code": "CA",
        "Lang": "EN"
      },
      {
        "Name": "Alaska",
        "Code": "AK",
        "Lang": "EN"
      },
      {
        "Name": "Texas",
        "Code": "TX",
        "Lang": "EN"
      }
    ]
  }
}

我正在查询此索引以按名称获取州计数的聚合。我正在使用以下查询:

{
  "from": 0,
  "size": 0,
  "query": {
    "query_string": {
      "query": "Country.State.Name: *Ala*"
    }
  },
  "aggs": {
    "counts": {
      "terms": {
        "field": "Country.State.Name.raw",
        "include": ".*Ala.*"
      }
    }
  }
}

在聚合方面,我只能使用 include 正则表达式获得与 query_string 匹配的键,但似乎无法在 include.[= 中使其不区分大小写。 16=]

我想要的结果是:

{
  "aggregations": {
    "counts": {
      "buckets": [
        {
          "key": "Alaska",
          "doc_count": 1
        }
      ]
    }
  }
}

是否有其他解决方案可以让我在不使用嵌套映射的情况下仅匹配 query_string 的键?

使用 Normalizer 作为关键字数据类型。下面是示例映射:

映射:

PUT country
{
  "settings": {
    "analysis": {
      "normalizer": {
        "my_normalizer": {                              <---- Note this
          "type": "custom",
          "filter": ["lowercase"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "Country": {
        "properties": {
          "State": {
            "properties": {
              "Name": {
                "type": "text",
                "fields": {
                  "raw": {
                    "type": "keyword",
                    "normalizer": "my_normalizer"      <---- Note this
                  }
                }
              },
              "Code": {
                "type": "text",
                "fields": {
                  "raw": {
                    "type": "keyword",
                    "normalizer": "my_normalizer"
                  }
                }
              },
              "Lang": {
                "type": "text",
                "fields": {
                  "raw": {
                    "type": "keyword",
                    "normalizer": "my_normalizer"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

文档:

POST country/_doc/1
{
  "Country": {
    "State": [
      {
        "Name": "California",
        "Code": "CA",
        "Lang": "EN"
      },
      {
        "Name": "Alaska",
        "Code": "AK",
        "Lang": "EN"
      },
      {
        "Name": "Texas",
        "Code": "TX",
        "Lang": "EN"
      }
    ]
  }
}

聚合查询:

POST country/_search
{
  "from": 0,
  "size": 0,
  "query": {
    "query_string": {
      "query": "Country.State.Name: *Ala*"
    }
  },
  "aggs": {
    "counts": {
      "terms": {
        "field": "Country.State.Name.raw",
        "include": "ala.*"
      }
    }
  }
}

注意 include 中的查询模式。基本上,由于我应用了规范化器,您拥有的 *.raw 字段的所有值都将存储在 lowercase letters 中。

回复:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "counts" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "alaska",
          "doc_count" : 1
        }
      ]
    }
  }
}

希望对您有所帮助!

我能够通过使用内联脚本过滤键来解决问题。 (仍然是一个肮脏的修复,但它现在解决了我的用例,我可以避免映射更改)

这是我执行查询的方式。

{
  "from": 0,
  "size": 0,
  "query": {
    "query_string": {
      "query": "Country.State.Name: *Ala*"
    }
  },
  "aggs": {
    "counts": {
      "terms": {
        "script": {
          "source": "doc['Country.State.Name.raw'].value.toLowerCase().contains('ala') ? doc['Country.State.Name.raw'].value : null",
          "lang": "painless"
        }
      }
    }
  }
}