Elasticsearch中多字段的条件聚合

时间:2014-07-10 20:20:55

标签: elasticsearch

这是我的ES索引中的文档示例:

{ 
    "concepts": [ 
        { 
            "type": "location",
            "entities": [ 
                { "text": "Raleigh" }, 
                { "text": "Damascus" }, 
                { "text": "Brussels" } 
            ] 
        }, 
        { 
            "type": "person", 
            "entities": [ 
                { "text": "Johnny Cash" }, 
                { "text": "Barack Obama" }, 
                { "text": "Vladimir Putin" }, 
                { "text": "John Hancock" } 
            ] 
        }, 
        { 
            "type": "organization", 
            "entities": [ 
                { "text": "WTO" }, 
                { "text": "IMF" }, 
                { "text": "United States of America" } 
            ] 
        } 
    ] 
}

我试图在我的文档集中聚合并计算每个概念实体的频率,以获取特定的概念类型。让我们说我只对聚合类型" location"的概念实体感兴趣。我的聚合桶随后将成为" concepts.entities.text",但我只想聚合它们,如果" concepts.type"等于" location"。这是我的尝试:

{
    "query": {
        // Whatever query
    },
    "aggs": {
        "location_concept_type": {
            "filter": {
                "term": { "concepts.type": "location" }
            },
            "aggs": {
                "entities": {
                    "terms": { "field": "concepts.hits.text" }
                }
            }
        }
    }
}

这样做的问题在于,它将过滤掉没有任何类型" location"的概念实体的文档。但对于那些确实具有类型" location" 其他东西,无论概念类型如何,它都会将所有概念实体存储起来。

我也试过通过以下方式重组我的文档:

{ 
    "concepts": [ 
        { 
            "type": "location",
            "text": "Raleigh"
        },
        { 
            "type": "location",
            "text": "Damascus"
        },
        { 
            "type": "location",
            "text": "Brussels"
        }, 
        { 
            "type": "person",
            "text": "Johnny Cash"
        },
        { 
            "type": "person",
            "text": "Barack Obama"
        }
        { 
            "type": "person",
            "text": "Vladimir Putin"
        }
        { 
            "type": "person",
            "text": "John Hancock"
        }, 
        { 
            "type": "organization",
            "text": "WTO" 
        },
        { 
            "type": "organization",
            "text": "IMF" 
        },
        { 
            "type": "organization",
            "text": "United States of America" 
        }
    ] 
}

但这也不起作用。最后,我不能使用概念类型作为键(我相信这将解决我的问题),因为我还需要能够聚合所有概念类型(并且可能存在无限且不断变化的概念类型)。 / p>

知道怎么办?在此先感谢您的帮助。

2 个答案:

答案 0 :(得分:3)

如果您按如下方式构建索引:

{ 
    "concepts": [ 
        { 
            "type": "location",
            "text": "Raleigh"
        },
        { 
            "type": "location",
            "text": "Damascus"
        }
    ]
}

并定义"概念"映射中的字段为嵌套对象,您可以应用以下搜索,在嵌套聚合中嵌套过滤器聚合

{
    "query": {
        "match_all": {}
    },
    "aggs": {
        "location_entities": {
            "nested": { "path": "concepts" }
        },
        "aggs": {
            "filtered_aggregation": {
                "filter": { "term": { "concepts.type": "location" } },
                "aggs": {
                    "my_aggregation": {
                        "terms": { "field": "concepts.text" }
                    }
                }
            }
        }
    }
}

在回复中,您知道您只获得了位置实体。这种方法比" hack"更快。在另一个答案中。

启动版本1.0.4Beta1,Elasticsearch提供filters aggregation。使用过滤器聚合替换嵌套聚合中的过滤器聚合,您可以按实体类型对您的聚合进行bucketize。

答案 1 :(得分:0)

我找到了一种破解方法。我会把它作为答案,但请随意添加另一个更优雅的答案。我所做的是在“type”和“text”旁边添加一个属性,我们称之为“text_exp”,它将类型和文本组合如下:

{
    "concepts": [
        { "type": "location", "text": "Raleigh", "text_exp": "location~Raleigh" },
        //...
    ]
}

然后我在聚合术语中使用正则表达式,如下所示。假设我只想聚合“location”类型的实体:

{
    "query": {
        // Whatever query
    },
    "aggs": {
        "location_entities": {
            "terms": { 
                "field": "concepts.text_exp",
                "include": "location~.*"
            }
        }
    }
}

然后在回复中我只是分开“〜”并采取正确的部分。