弹性搜索嵌套过滤器是包容性的和排他性的 [英] Elasticsearch Nested Filters being inclusive vs. exclusive
问题描述
我有一个对象映射,使用嵌套对象(在我们的示例中为 props
),采用标记方式。
每个标签都可以属于客户端/用户,当我们希望允许我们的用户使用 props.name生成
。 query_string
样式搜索
问题是当我们运行我们的查询,如果一个对象有多个道具,如果其中许多道具之一匹配过滤器,其他人对象被返回,当我们想要相反的时候 - 如果一个返回false,那么返回不会返回,如果返回true。
我已经发布了一个全面的例子这里: https://gist.github.com/d2kagw/1c9d4ef486b7a2450d95
提前感谢
我相信这可能需要一个扁平化列表的优势的值,像一个数组。数组和嵌套对象之间的主要区别在于后者知道嵌套属性的哪个值对应于相同嵌套对象中另一个属性的另一个值。另一方面,数组的值会使某个属性的值变平,并且您将丢失 client_id
和名称之间的关联 / code>。意思是使用数组,你有
props.client_id = [null,2]
和 props.name = [petlover,premiumshopper code>。
使用嵌套
过滤器,您需要将该字符串与道具的所有值相匹配。一个父文档的 c
props.name
需要匹配。那么嵌套对象不会发生这种情况,因为嵌套的文档是分开的并且被单独查询。而且,如果至少有一个嵌套文档匹配,那么它被认为是一个匹配。
换句话说,对于像query:props .name:(carlover NOT petlover)
你基本上需要按照一个扁平化的值列表运行它,就像数组一样。您需要对[carlover,petlover]进行查询。
我的建议是让您的嵌套文档include_in_parent :true
(意思是保持在一个扁平化的数组列表中)并更改一些查询:
- $ b $对于
- ,使用展平属性方法能够将元素的组合列表的查询匹配,而不是逐个元素。
- 为
匹配
(或术语
,见下文)和缺少
零件使用嵌套属性方法,因为您可以在其中有null
s。数组中的缺少
只有当整个数组丢失时才匹配,而不是其中的一个值,所以这里不能使用与查询相同的方法,其中值$>
- 可选,但对于
查询
匹配
整数我将使用术语
,因为它不是字符串,而是整数,默认情况下not_analyzed
。
query_string
部分的b 正如上所述,这些更改是这些更改:
code> {
mappings:{
...
props:{
type:nested,
include_in_parent :true,
...
- 应该)返回零结果
GET / nesting-test / _search?pretty = true
{
查询:{
过滤:{
过滤器:{
和:[
{
query:{
qu red_string:{query:props.name:((clover and premiumshopper)NOT petlover)}
}
},
{
嵌套:{
path:props,
filter:{
or:[{query:{match:{props.client_id:1}}} ,{missing:{field:props.client_id}}]
}
}
}
]
}
}
}
}
<应该(并且)只返回1
GET /嵌套测试/ _search?pretty = true
{
查询:{
filters:{
filter:{
and
{query:{query_string:{query:props.name:(carlover NOT petlover)}}},
{
嵌套:{
path:props,
filter:{
或:[{query:{matc h:{props.client_id:1}}},{missing:{field:props.client_id}}]
}
}
}
]
}
}
}
}
< ol start =3>
GET / nesting-test / _search?pretty = true
{
query:{
filtered:{
filter:{
and:[
{query:{query_string:{query:props.name:(* NOT carlover)}}},
{
nested:{
path:props,
filter:{
or:[{query:{term :{props.client_id:1}}},{missing:{field:props.client_id}}
]
}
}
}
]
}
}
}
}
I have an object mapping that uses nested objects (props
in our example) in a tag-like fashion.
Each tag can belong to a client/user and when we want to allow our users to generate query_string
style searches against the props.name
.
Issue is that when we run our query if an object has multiple props and if one of the many props match the filter when others don't the object is returned, when we want the opposite - if one returns false don't return vs. if one returns true return.
I have posted a comprehensive example here: https://gist.github.com/d2kagw/1c9d4ef486b7a2450d95
Thanks in advance.
I believe here you might need the advantage of a flattened list of values, like an array of values. The major difference between an array and nested objects is that the latter "knows" which value of a nested property corresponds to another value of another property in the same nested object. The array of values, on the other hand will flatten the values of a certain property and you lose the "association" between a client_id
and a name
. Meaning, with arrays you have props.client_id = [null, 2]
and props.name = ["petlover", "premiumshopper"]
.
With your nested
filter you want to match that string to all values for props.name
meaning ALL nested props.name
s of one parent doc needs to match. Well, this doesn't happen with nested objects, because the nested documents are separate and are queried separately. And, if at least one nested document matches then it's considered a match.
In other words, for a query like "query": "props.name:(carlover NOT petlover)"
you basically need to run it against a flattened list of values, just like arrays. You need that query ran against ["carlover", "petlover"].
My suggestion for you is to make your nested documents "include_in_parent": true
(meaning, keep in parent a flattened, array-like list of values) and change a bit the queries:
- for the
query_string
part, use the flattened properties approach to be able to match your query for a combined list of elements, not element by element. - for the
match
(orterm
, see below) andmissing
parts use the nested properties approach because you can havenull
s in there. Amissing
on an array will match only if the whole array is missing, not one value in it, so here one cannot use the same approach as for the query, where the values were flattened in an array. - optional, but for the
query
match
integer I would useterm
, as it's not string but integer and is by defaultnot_analyzed
.
These being said, with the above changes, these are the changes:
{
"mappings" : {
...
"props": {
"type": "nested",
"include_in_parent": true,
...
- should (and does) return zero results
GET /nesting-test/_search?pretty=true
{
"query": {
"filtered": {
"filter": {
"and": [
{
"query": {
"query_string": { "query": "props.name:((carlover AND premiumshopper) NOT petlover)" }
}
},
{
"nested": {
"path": "props",
"filter": {
"or": [ { "query": { "match": { "props.client_id": 1 } } }, { "missing": { "field": "props.client_id" } } ]
}
}
}
]
}
}
}
}
- should (and does) return just 1
GET /nesting-test/_search?pretty=true
{
"query": {
"filtered": {
"filter": {
"and": [
{"query": {"query_string": { "query": "props.name:(carlover NOT petlover)" } } },
{
"nested": {
"path": "props",
"filter": {
"or": [{ "query": { "match": { "props.client_id": 1 } } },{ "missing": { "field": "props.client_id" } } ]
}
}
}
]
}
}
}
}
- should (and does) return just 2
GET /nesting-test/_search?pretty=true
{
"query": {
"filtered": {
"filter": {
"and": [
{ "query": {"query_string": { "query": "props.name:(* NOT carlover)" } } },
{
"nested": {
"path": "props",
"filter": {
"or": [{ "query": { "term": { "props.client_id": 1 } } },{ "missing": { "field": "props.client_id" } }
]
}
}
}
]
}
}
}
}
这篇关于弹性搜索嵌套过滤器是包容性的和排他性的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!