Title: is_empty filter behaves differently depending on whether the field is indexed
There are 2 ways to check whether a payload field is empty.
{"must":[{"is_empty":{"key":<key>}}]}
and
{"must":[{"key":<key>,"is_empty":true}]}.
On a key that resolves to a single value the two forms agree. On a key that resolves to several values they do not, and one of them also depends on whether the field is indexed.
If a payload field is not indexed and {"must":[{"key":<key>,"is_empty":true}]} is used, then this filter matches a point when any value at the key is empty, so it matches a[].b on {"a": [{"b": 1}, {"b": []}]}. In all the other cases (when the field is indexed, or when the {"must":[{"is_empty":{"key":<key>}}]} form is used) the filter matches only when every value at the key is empty, so that point does not match.
This issue looks similar to #10096 Steps to reproduce:
PUT collections/indexed
{
"vectors": {
"distance": "Dot",
"size": 2
}
}
PUT collections/unindexed
{
"vectors": {
"distance": "Dot",
"size": 2
}
}
PUT collections/indexed/index
{
"field_name": "a[].b",
"field_schema": "integer"
}
PUT collections/indexed/points
{
"points": [
{
"id": 1,
"payload": {
"a": [
{
"b": 1
},
{
"b": []
}
]
},
"vector": [
0.2,
0.3
]
},
{
"id": 2,
"payload": {
"a": [
{
"b": 1
},
{
"b": null
}
]
},
"vector": [
0.2,
0.4
]
},
{
"id": 3,
"payload": {
"a": [
{
"b": 1
},
{
"b": 2
}
]
},
"vector": [
0.1,
0.4
]
},
{
"id": 4,
"payload": {
"a": [
{
"b": []
},
{
"b": []
}
]
},
"vector": [
0.1,
0.5
]
}
]
}
PUT collections/unindexed/points
{
"points": [
{
"id": 1,
"payload": {
"a": [
{
"b": 1
},
{
"b": []
}
]
},
"vector": [
0.2,
0.3
]
},
{
"id": 2,
"payload": {
"a": [
{
"b": 1
},
{
"b": null
}
]
},
"vector": [
0.2,
0.4
]
},
{
"id": 3,
"payload": {
"a": [
{
"b": 1
},
{
"b": 2
}
]
},
"vector": [
0.1,
0.4
]
},
{
"id": 4,
"payload": {
"a": [
{
"b": []
},
{
"b": []
}
]
},
"vector": [
0.1,
0.5
]
}
]
}
POST collections/indexed/points/scroll
{
"filter": {"must":[{"is_empty":{"key":"a[].b"}}]}
}
POST collections/unindexed/points/scroll
{
"filter": {"must":[{"is_empty":{"key":"a[].b"}}]}
}
POST collections/indexed/points/scroll
{
"filter": {"must":[{"key":"a[].b","is_empty":true}]}
}
POST collections/unindexed/points/scroll
{
"filter": {"must":[{"key":"a[].b","is_empty":true}]}
}Source: qdrant/qdrant