【问题标题】:Elasticsearch fielddata - should I use it?Elasticsearch fielddata - 我应该使用它吗?
【发布时间】:2022-01-26 19:47:56
【问题描述】:

给定一个包含具有 brand 属性的文档的索引,我们需要创建一个不区分大小写的术语聚合。

索引定义

请注意fielddata

的使用
PUT demo_products
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_custom_analyzer": {
          "type": "custom",
          "tokenizer": "keyword",
          "filter": [
            "lowercase"
          ]
        }
      }
    }
  },
  "mappings": {
    "product": {
      "properties": {
        "brand": {
          "type": "text",
          "analyzer": "my_custom_analyzer",
          "fielddata": true,
        }
      }
    }
  }
}

数据

POST demo_products/product
{
  "brand": "New York Jets"
}

POST demo_products/product
{
  "brand": "new york jets"
}

POST demo_products/product
{
  "brand": "Washington Redskins"
}

查询

GET demo_products/product/_search
{
  "size": 0,
  "aggs": {
    "brand_facet": {
      "terms": {
        "field": "brand"
      }
    }
  }
}

结果

"aggregations": {
    "brand_facet": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "new york jets",
          "doc_count": 2
        },
        {
          "key": "washington redskins",
          "doc_count": 1
        }
      ]
    }
  }

如果我们使用keyword 而不是text,由于外壳的不同,我们最终会得到 2 个纽约喷气机的桶。

我们担心使用 fielddata 会影响性能。但是,如果禁用了 fielddata,我们会得到可怕的“默认情况下在文本字段上禁用 Fielddata。”

任何其他解决此问题的技巧 - 还是我们不应该如此担心 fielddate?

【问题讨论】:

  • 托管 ES 实例的机器有多大(CPU、内存)?我们在谈论多少个文件?有多少个索引?
  • 300.000 个文档分为 28 个索引,弹性云托管(3 个服务器,目前 4 GB)
  • 嗯,为什么这么少的文档有这么多索引?
  • 两个选项:要么在单个案例中索引所有内容,然后使用 keyword(和 doc_values,而不是 fielddata)。第二种选择:使用 my_custom_analyzer 分析器将所有内容设为小写并使用 fielddata。 Fielddata 被认为是一种不好的方法,而且在很多情况下都是如此。但是,如果您的节点可以处理负载(内存方面)并且考虑到正在使用的 fielddata 内存量,那么为什么不使用 fielddata?
  • Fielddata 是好的,直到你有内存压力。如果您确实有记忆问题,那么您需要开始寻找改善这种情况的方法。而fielddata通常是第一个可以调整的。

标签: elasticsearch


【解决方案1】:

从 ES 5.2(今天发布)开始,您可以使用 normalizerskeyword 字段来(例如)小写值。

规范化器的作用有点像 text 字段的分析器,虽然你可以用它们做的事情更受限制,但这可能有助于解决你面临的问题。

你会像这样创建索引:

PUT demo_products
{
  "settings": {
    "analysis": {
      "normalizer": {
        "my_normalizer": {
          "type": "custom",
          "filter": [ "lowercase" ]
        }
      }
    }
  },
  "mappings": {
    "product": {
      "properties": {
        "brand": {
          "type": "keyword",
          "normalizer": "my_normalizer"
        }
      }
    }
  }
}

您的查询将返回:

  "aggregations" : {
    "brand_facet" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "new york jets",
          "doc_count" : 2
        },
        {
          "key" : "washington redskins",
          "doc_count" : 1
        }
      ]
    }
  }

两全其美!

【讨论】:

  • 插入数据时可以指定吗?而不是发出单独的PUT 请求。
  • @JayPatel 不行,你需要先创建索引
【解决方案2】:

如果您使用脚本,您可以在查询时小写聚合。它的性能不如规范化的关键字字段,但在我的经验中仍然相当快。例如,您的查询是:

GET demo_products/product/_search
{
  "size": 0,
  "aggs": {
    "brand_facet": {
      "terms": {
        "script": "doc['brand'].value.toLowerCase()"
      }
    }
  }
}

【讨论】:

    猜你喜欢
    • 2012-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-03
    • 2019-06-11
    • 2012-12-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多