【问题标题】:Best way to index arbitrary attribute value pairs on elastic search在弹性搜索中索引任意属性值对的最佳方法
【发布时间】:2015-04-19 11:25:42
【问题描述】:

我正在尝试对具有属性值对的弹性搜索文档进行索引。示例文档:

{
    id: 1,
    name: "metamorphosis",
    author: "franz kafka"
}

{
    id: 2,
    name: "techcorp laptop model x",
    type: "computer",
    memorygb: 4
}

{
    id: 3,
    name: "ss2014 formal shoe x",
    color: "black",
    size: 42,
    price: 124.99
}

然后,我需要这样的查询:

1. "author" EQUALS "franz kafka"
2. "type" EQUALS "computer" AND "memorygb" GREATER THAN 4
3. "color" EQUALS "black" OR ("size" EQUALS 42 AND price LESS THAN 200.00)

存储这些文档以有效查询它们的最佳方式是什么?我应该完全按照示例中所示存储它们吗?或者我应该像这样存储它们:

{
    fields: [
        { "type": "computer" },
        { "memorygb": 4 }
    ]
}

或喜欢:

{
    fields: [
        { "key": "type", "value": "computer" },
        { "key": "memorygb", "value": 4 }
    ]
}

我应该如何映射我的索引才能同时执行我的相等和范围查询?

【问题讨论】:

    标签: elasticsearch elasticsearch-indices


    【解决方案1】:

    如果有人还在寻找答案,我写了一篇关于如何将任意数据索引到 Elasticsearch 中然后按特定字段和值进行搜索的帖子。所有这一切,都不会破坏您的索引映射。

    发帖:http://smnh.me/indexing-and-searching-arbitrary-json-data-using-elasticsearch/

    简而言之,您需要创建帖子中描述的特殊索引。然后您需要使用flattenData 函数https://gist.github.com/smnh/30f96028511e1440b7b02ea559858af4 展平您的数据。然后,扁平化的数据可以安全地索引到 Elasticsearch 索引中。

    例如:

    flattenData({
        id: 1,
        name: "metamorphosis",
        author: "franz kafka"
    });
    

    将产生:

    [
        {
            "key": "id",
            "type": "long",
            "key_type": "id.long",
            "value_long": 1
        },
        {
            "key": "name",
            "type": "string",
            "key_type": "name.string",
            "value_string": "metamorphosis"
        },
        {
            "key": "author",
            "type": "string",
            "key_type": "author.string",
            "value_string": "franz kafka"
        }
    ]
    

    并且

    flattenData({
        id: 2,
        name: "techcorp laptop model x",
        type: "computer",
        memorygb: 4
    });
    

    将产生:

    [
        {
            "key": "id",
            "type": "long",
            "key_type": "id.long",
            "value_long": 2
        },
        {
            "key": "name",
            "type": "string",
            "key_type": "name.string",
            "value_string": "techcorp laptop model x"
        },
        {
            "key": "type",
            "type": "string",
            "key_type": "type.string",
            "value_string": "computer"
        },
        {
            "key": "memorygb",
            "type": "long",
            "key_type": "memorygb.long",
            "value_long": 4
        }
    ]
    

    然后您可以使用构建 Elasticsearch 查询来查询您的数据。每个查询都应该指定键和值的类型。如果您不确定索引有哪些键或类型,可以运行聚合来找出,这也在帖子中讨论。

    例如,要查找author == "franz kafka" 所在的文档,您需要执行以下查询:

    {
        "query": {
            "nested": {
                "path": "flatData",
                "query": {
                    "bool": {
                        "must": [
                            {"term": {"flatData.key": "author"}},
                            {"match": {"flatData.value_string": "franz kafka"}}
                        ]
                    }
                }
            }
        }
    }
    

    要查找type == "computer" and memorygb > 4 所在的文档,您需要执行以下查询:

    {
        "query": {
            "bool": {
                "must": [
                    {
                        "nested": {
                            "path": "flatData",
                            "query": {
                                "bool": {
                                    "must": [
                                        {"term": {"flatData.key": "type"}},
                                        {"match": {"flatData.value_string": "computer"}}
                                    ]
                                }
                            }
                        }
                    },
                    {
                        "nested": {
                            "path": "flatData",
                            "query": {
                                "bool": {
                                    "must": [
                                        {"term": {"flatData.key": "memorygb"}},
                                        {"range": {"flatData.value_long": {"gt": 4}}}
                                    ]
                                }
                            }
                        }
                    }
                ]
            }
        }
    }
    

    在这里,因为我们希望同一个文档同时匹配两个条件,所以我们使用外部 bool 查询和一个包含两个 nested 查询的 must 子句。

    【讨论】:

    • 如果字段/属性的数量非常多,比如数千,这将非常有用。但是如果字段是任意的,但仍然限制在 100 甚至 200,那么我认为 ElasticSearch 的 DynamicMapping 就足够了。
    【解决方案2】:

    Elastic Search 是一种无模式数据存储,它允许对新属性进行动态索引,并且具有可选字段不会影响性能。您的第一个映射绝对没问题,您可以围绕动态属性进行布尔查询。 将它们设置为嵌套字段并没有内在的性能优势,它们无论如何都会在 fields.type 、 fields.memorygb 等索引上变平。

    相反,您尝试存储为键值对的最后一个映射将对性能产生影响,因为您必须查询 2 个不同的索引字段,即 key='memorygb' 和 value =4

    查看有关动态映射的文档:

    Elasticsearch 最重要的特性之一是它能够无模式。如果一个对象是没有性能开销的 动态,能力 将其关闭是作为安全机制提供的,因此“格式错误” 对象不会错误地索引我们不希望的数据 索引。

    http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-object-type.html

    【讨论】:

    • 第一个映射直到某个点都可以,如果任意键的数量不断增加(例如使用 UUID 作为字段名) Elasticsearch 可能会遇到映射爆炸,这就是为什么从ES ~5,映射的默认限制为 1000(在index.mapping.total_fields 中设置)。
    【解决方案3】:

    您需要来自here 的过滤查询外观:

    你必须同时使用范围查询和匹配查询

    【讨论】:

    • 这很明显,但我正在寻找的不是如何查询我的文档,而是如何为高性能查询构建它们。
    • 看这里stackoverflow.com/a/22224568/3835610,我建议你使用Hadoop。我的朋友已经用 hadoop 解决了速度慢的问题,并推荐了一些技巧,比如loggly.com/blog/…
    猜你喜欢
    • 1970-01-01
    • 2013-10-09
    • 2018-05-12
    • 1970-01-01
    • 1970-01-01
    • 2016-03-28
    • 2016-10-24
    相关资源
    最近更新 更多