【问题标题】:How to search through data with arbitrary amount of fields?如何搜索具有任意数量字段的数据?
【发布时间】:2014-10-10 11:17:15
【问题描述】:

我有用于科学活动的网络表单生成器。活动主持人创建具有任意数量的布尔、整数、枚举和文本字段的注册表。

创建的表单用于:

  • 为活动注册新成员;
  • 搜索注册会员。

第二个任务(搜索活动成员)的最佳搜索工具是什么? ElasticSearch 是否适合这项任务?

【问题讨论】:

  • 那么,您要索引什么类型的数据?我认为您想在飞行中添加新字段并使用这些字段进行搜索?我对么?如果是,那么答案是肯定的。

标签: search elasticsearch full-text-search search-engine


【解决方案1】:

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

帖子在这里:http://smnh.me/indexing-and-searching-arbitrary-json-data-using-elasticsearch/

简而言之,您需要执行以下步骤才能获得所需的内容:

  1. 创建帖子中描述的特殊索引。
  2. 使用flattenData 函数展平要索引的数据:
    https://gist.github.com/smnh/30f96028511e1440b7b02ea559858af4
  3. 使用原始数据和展平数据创建一个文档并将其索引到 Elasticsearch:

    {
        "data": { ... },
        "flatData": [ ... ]
    }
    
  4. 可选:使用 Elasticsearch 聚合来查找已索引的字段和类型。

  5. flatData 对象执行查询以找到您需要的内容。

示例

根据您最初的问题,假设第一位活动主持人创建了一个包含以下字段的表单来注册科学活动的成员:

  • name 字符串
  • age
  • sex long - 0 男性,1 女性

除了这些数据,相关事件可能还有某种id,我们称之为eventId。所以最终的文档可能如下所示:

{
    "eventId": "2T73ZT1R463DJNWE36IA8FEN",
    "name": "Bob",
    "age": 22,
    "sex": 0
}

现在,在我们索引此文档之前,我们将使用 flattenData 函数将其展平:

flattenData(document);

这将产生以下数组:

[
    {
        "key": "eventId",
        "type": "string",
        "key_type": "eventId.string",
        "value_string": "2T73ZT1R463DJNWE36IA8FEN"
    },
    {
        "key": "name",
        "type": "string",
        "key_type": "name.string",
        "value_string": "Bob"
    },
    {
        "key": "age",
        "type": "long",
        "key_type": "age.long",
        "value_long": 22
    },
    {
        "key": "sex",
        "type": "long",
        "key_type": "sex.long",
        "value_long": 0
    }
]

然后我们将这些数据包装在一个文档中,就像我之前展示的那样,并对其进行索引。

然后,第二个活动主持人创建另一个表单,该表单具有一个新字段,具有相同名称和类型的字段,以及一个具有相同名称但具有不同类型的字段:

  • name 字符串
  • city 字符串
  • sex 字符串 - “男”或“女”

这位活动主持人决定不再使用01 来表示男性和女性,而是允许在两个字符串之间进行选择——“男性”和“女性”。

让我们尝试将这个表单提交的数据展平:

flattenData({
    "eventId": "F1BU9GGK5IX3ZWOLGCE3I5ML",
    "name": "Alice",
    "city": "New York",
    "sex": "female"
});

这将产生以下数据:

[
    {
        "key": "eventId",
        "type": "string",
        "key_type": "eventId.string",
        "value_string": "F1BU9GGK5IX3ZWOLGCE3I5ML"
    },
    {
        "key": "name",
        "type": "string",
        "key_type": "name.string",
        "value_string": "Alice"
    },
    {
        "key": "city",
        "type": "string",
        "key_type": "city.string",
        "value_string": "New York"
    },
    {
        "key": "sex",
        "type": "string",
        "key_type": "sex.string",
        "value_string": "female"
    }
]

然后,在将扁平化数据包装到文档中并将其索引到 Elasticsearch 中之后,我们可以执行复杂的查询。

例如,要查找为 ID 2T73ZT1R463DJNWE36IA8FEN 注册的名为“Bob”的成员,我们可以执行以下查询:

{
    "query": {
        "bool": {
            "must": [
                {
                    "nested": {
                        "path": "flatData",
                        "query": {
                            "bool": {
                                "must": [
                                    {"term": {"flatData.key": "eventId"}},
                                    {"match": {"flatData.value_string.keyword": "2T73ZT1R463DJNWE36IA8FEN"}}
                                ]
                            }
                        }
                    }
                },
                {
                    "nested": {
                        "path": "flatData",
                        "query": {
                            "bool": {
                                "must": [
                                    {"term": {"flatData.key": "name"}},
                                    {"match": {"flatData.value_string": "bob"}}
                                ]
                            }
                        }
                    }
                }
            ]
        }
    }
}

【讨论】:

  • 在我看来,这应该是公认的答案。它有助于我的情况,这与这个问题非常相似。很高兴成为第一个支持这个答案的人:)
【解决方案2】:

ElasticSearch 会自动检测字段内容以便对其进行正确索引,即使之前尚未定义映射也是如此。所以,是的:ElasticSearch 非常适合这些情况。

但是,您可能需要微调此行为,或者 ElasticSearch 应用的默认映射可能与您需要的不对应:在这种情况下,请查看 default mapping,或者,为了进一步控制, dynamic templates 功能。

【讨论】:

    【解决方案3】:

    如果您让最终用户决定存储内容的,您将拥有不断增长的映射和集群状态,这是有问题的。

    article on common problems with Elasticsearch 涵盖了此案例和建议的解决方案。

    本质上,您希望将所有可能被用户定义为值的东西。使用嵌套文档,您可以使用 key-field 和不同映射的值字段来实现几乎相同的效果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-14
      • 2021-12-24
      • 2013-02-02
      • 1970-01-01
      • 1970-01-01
      • 2015-12-04
      • 2016-05-13
      • 1970-01-01
      相关资源
      最近更新 更多