Spaces:
Build error
Build error
import pytest | |
from .helpers.collection_setup import drop_collection | |
from .helpers.helpers import request_with_validation | |
from .test_nested_payload_indexing import nested_payload_collection_setup | |
def setup(on_disk_vectors, on_disk_payload, collection_name): | |
nested_payload_collection_setup(collection_name=collection_name, on_disk_vectors=on_disk_vectors, on_disk_payload=on_disk_payload) | |
yield | |
drop_collection(collection_name=collection_name) | |
def test_nested_payload_indexing_operations(collection_name): | |
response = request_with_validation( | |
api='/collections/{collection_name}', | |
method="GET", | |
path_params={'collection_name': collection_name}, | |
) | |
assert response.ok | |
# Create nested index | |
response = request_with_validation( | |
api='/collections/{collection_name}/index', | |
method="PUT", | |
path_params={'collection_name': collection_name}, | |
query_params={'wait': 'true'}, | |
body={ | |
"field_name": "country.capital", | |
"field_schema": "keyword" | |
} | |
) | |
assert response.ok | |
# Create nested array index | |
response = request_with_validation( | |
api='/collections/{collection_name}/index', | |
method="PUT", | |
path_params={'collection_name': collection_name}, | |
query_params={'wait': 'true'}, | |
body={ | |
"field_name": "country.cities[].population", | |
"field_schema": "float" | |
} | |
) | |
assert response.ok | |
# Validate index creation | |
response = request_with_validation( | |
api='/collections/{collection_name}', | |
method="GET", | |
path_params={'collection_name': collection_name}, | |
) | |
assert response.ok | |
assert response.json()['result']['payload_schema']['country.capital']['data_type'] == "keyword" | |
assert response.json()['result']['payload_schema']['country.capital']['points'] == 4 | |
assert response.json()['result']['payload_schema']['country.cities[].population']['data_type'] == "float" | |
assert response.json()['result']['payload_schema']['country.cities[].population']['points'] == 4 # indexed records | |
# Search nested array without payload index | |
response = request_with_validation( | |
api='/collections/{collection_name}/points/scroll', | |
method="POST", | |
path_params={'collection_name': collection_name}, | |
body={ | |
"filter": { | |
"must": [ | |
{ | |
"nested": { | |
"key": "country.cities[]", | |
"filter": { | |
"must": [ | |
{ | |
"key": "population", | |
"range": { | |
"gte": 9.0, | |
} | |
} | |
] | |
} | |
} | |
} | |
] | |
}, | |
"limit": 3 | |
} | |
) | |
assert response.ok | |
assert len(response.json()['result']['points']) == 1 | |
# Search nested array without payload index (implicit array key) | |
response = request_with_validation( | |
api='/collections/{collection_name}/points/scroll', | |
method="POST", | |
path_params={'collection_name': collection_name}, | |
body={ | |
"filter": { | |
"must": [ | |
{ | |
"nested": { | |
"key": "country.cities", # implicitly add array [] to key | |
"filter": { | |
"must": [ | |
{ | |
"key": "population", | |
"range": { | |
"gte": 9.0, | |
} | |
} | |
] | |
} | |
} | |
} | |
] | |
}, | |
"limit": 3 | |
} | |
) | |
assert response.ok | |
assert len(response.json()['result']['points']) == 1 | |
# Search with nested filter on non indexed payload | |
response = request_with_validation( | |
api='/collections/{collection_name}/points/scroll', | |
method="POST", | |
path_params={'collection_name': collection_name}, | |
body={ | |
"filter": { | |
"must": [ | |
{ | |
"nested": { | |
"key": "country.cities", | |
"filter": { | |
"must": [ | |
{ | |
"must": [ | |
{ | |
"key": "sightseeing", | |
"values_count": { | |
"gt": 3 | |
} | |
} | |
] | |
} | |
] | |
} | |
} | |
} | |
] | |
}, | |
"limit": 3 | |
} | |
) | |
assert response.ok | |
assert len(response.json()['result']['points']) == 1 | |
assert response.json()['result']['points'][0]['payload']['country']['name'] == "France" | |
# Search with nested filter and must-not | |
response = request_with_validation( | |
api='/collections/{collection_name}/points/scroll', | |
method="POST", | |
path_params={'collection_name': collection_name}, | |
body={ | |
"filter": { | |
"must": [ | |
{ | |
"nested": { | |
"key": "country.cities", | |
"filter": { | |
"must": [ | |
{ | |
"key": "population", | |
"range": { | |
"gte": 9.0, | |
} | |
} | |
], | |
"must_not": [ | |
{ | |
"key": "sightseeing", | |
"values_count": { | |
"gt": 1 | |
} | |
} | |
] | |
} | |
} | |
} | |
] | |
}, | |
"limit": 3 | |
} | |
) | |
assert response.ok | |
assert len(response.json()['result']['points']) == 0 | |
# Search with nested filter on indexed payload | |
response = request_with_validation( | |
api='/collections/{collection_name}/points/scroll', | |
method="POST", | |
path_params={'collection_name': collection_name}, | |
body={ | |
"filter": { | |
"must": [ | |
{ | |
"nested": { | |
"key": "country.cities", | |
"filter": { | |
"must": [ | |
{ | |
"key": "population", | |
"range": { | |
"gte": 9.0, | |
} | |
} | |
] | |
} | |
} | |
} | |
] | |
}, | |
"limit": 3 | |
} | |
) | |
assert response.ok | |
assert len(response.json()['result']['points']) == 1 | |
assert response.json()['result']['points'][0]['payload']['country']['name'] == "Japan" | |
# Search with nested filter on indexed & non payload (match only within point) | |
response = request_with_validation( | |
api='/collections/{collection_name}/points/scroll', | |
method="POST", | |
path_params={'collection_name': collection_name}, | |
body={ | |
"filter": { | |
"must": [ | |
{ | |
"nested": { | |
"key": "country.cities", | |
"filter": { | |
"must": [ | |
{ | |
"key": "population", | |
"range": { | |
"gte": 9.0, | |
} | |
}, | |
{ | |
"key": "sightseeing", | |
"values_count": { | |
"gt": 2 | |
} | |
} | |
] | |
} | |
} | |
} | |
] | |
}, | |
"limit": 3 | |
} | |
) | |
assert response.ok | |
# No single point has in its payload a city with more than 8M inhabitants AND more than 2 sightseeing | |
# Japan has 9M inhabitants but only 2 sightseeing | |
# London & Paris have 3 sightseeing but less 9M inhabitants | |
assert len(response.json()['result']['points']) == 0 | |
# Search with nested filter on indexed & non payload | |
response = request_with_validation( | |
api='/collections/{collection_name}/points/scroll', | |
method="POST", | |
path_params={'collection_name': collection_name}, | |
body={ | |
"filter": { | |
"must": [ | |
{ | |
"nested": { | |
"key": "country.cities", | |
"filter": { | |
"must": [ | |
{ | |
"key": "population", | |
"range": { | |
"gte": 8.0, | |
} | |
}, | |
{ | |
"key": "sightseeing", | |
"values_count": { | |
"lt": 3 | |
} | |
} | |
] | |
} | |
} | |
} | |
] | |
}, | |
"limit": 3 | |
} | |
) | |
assert response.ok | |
assert len(response.json()['result']['points']) == 1 | |
# Only Tokio has more than 8M inhabitants and less than 3 sightseeing | |
assert response.json()['result']['points'][0]['payload']['country']['name'] == "Japan" | |
# Search with nested filter on indexed & non payload (must_not) | |
response = request_with_validation( | |
api='/collections/{collection_name}/points/scroll', | |
method="POST", | |
path_params={'collection_name': collection_name}, | |
body={ | |
"filter": { | |
"must": [ | |
{ | |
"nested": { | |
"key": "country.cities", | |
"filter": { | |
"must_not": [ | |
{ | |
"key": "population", | |
"range": { | |
"lt": 8.0, | |
} | |
}, | |
{ | |
"is_null": { | |
"key": "name" | |
} | |
} | |
], | |
} | |
} | |
} | |
] | |
}, | |
"limit": 3 | |
} | |
) | |
assert response.ok | |
assert len(response.json()['result']['points']) == 2 | |
# Only 2 records that do NOT have at least one city population < 8.0 | |
assert response.json()['result']['points'][0]['payload']['country']['name'] == "England" # London | |
assert response.json()['result']['points'][1]['payload']['country']['name'] == "Japan" # Tokyo | |
# Search with nested filter on indexed & non payload (must_not) | |
response = request_with_validation( | |
api='/collections/{collection_name}/points/scroll', | |
method="POST", | |
path_params={'collection_name': collection_name}, | |
body={ | |
"filter": { | |
"must": [ | |
{ | |
"nested": { | |
"key": "country.cities", | |
"filter": { | |
"must_not": [ | |
{ | |
"key": "population", | |
"range": { | |
"lt": 8.0, | |
} | |
}, | |
{ | |
"key": "sightseeing", | |
"values_count": { | |
"gte": 3 | |
} | |
}, | |
{ | |
"is_null": { | |
"key": "name" | |
} | |
} | |
] | |
} | |
} | |
} | |
] | |
}, | |
"limit": 3 | |
} | |
) | |
assert response.ok | |
assert len(response.json()['result']['points']) == 1 | |
# Only 1 record that do NOT have at least one city population < 8.0 and NOT more than 3 sightseeing | |
assert response.json()['result']['points'][0]['payload']['country']['name'] == "Japan" # Tokyo | |
# Search nested null field | |
response = request_with_validation( | |
api='/collections/{collection_name}/points/scroll', | |
method="POST", | |
path_params={'collection_name': collection_name}, | |
body={ | |
"filter": { | |
"must": [ | |
{ | |
"nested": { | |
"key": "country.cities", | |
"filter": { | |
"must": [ | |
{ | |
"is_null": { | |
"key": "name" | |
} | |
} | |
] | |
} | |
} | |
} | |
] | |
}, | |
"limit": 3 | |
} | |
) | |
assert response.ok | |
assert len(response.json()['result']['points']) == 1 | |
assert response.json()['result']['points'][0]['payload']['country']['name'] == "Nauru" | |
# Search nested geobox field | |
geo_box_berlin = { | |
"bottom_right": { | |
"lon": 13.76117, | |
"lat": 52.33825, | |
}, | |
"top_left": { | |
"lon": 13.08835, | |
"lat": 52.67551, | |
} | |
} | |
response = request_with_validation( | |
api='/collections/{collection_name}/points/scroll', | |
method="POST", | |
path_params={'collection_name': collection_name}, | |
body={ | |
"filter": { | |
"must": [ | |
{ | |
"nested": { | |
"key": "country.cities", | |
"filter": { | |
"must": [ | |
{ | |
"key": "location", | |
"geo_bounding_box": geo_box_berlin | |
} | |
] | |
} | |
} | |
} | |
] | |
}, | |
"limit": 3 | |
} | |
) | |
assert response.ok | |
assert len(response.json()['result']['points']) == 1 | |
assert response.json()['result']['points'][0]['payload']['country']['name'] == "Germany" | |
# Search nested geo-radius field | |
berlin_center = { | |
"lon": 13.76117, | |
"lat": 52.33825, | |
} | |
response = request_with_validation( | |
api='/collections/{collection_name}/points/scroll', | |
method="POST", | |
path_params={'collection_name': collection_name}, | |
body={ | |
"filter": { | |
"must": [ | |
{ | |
"nested": { | |
"key": "country.cities", | |
"filter": { | |
"must": [ | |
{ | |
"key": "location", | |
"geo_radius": { | |
"center": berlin_center, | |
"radius": 1000, # meters | |
} | |
} | |
] | |
} | |
} | |
} | |
] | |
}, | |
"limit": 3 | |
} | |
) | |
assert response.ok | |
assert len(response.json()['result']['points']) == 1 | |
assert response.json()['result']['points'][0]['payload']['country']['name'] == "Germany" | |
# Delete indexes | |
response = request_with_validation( | |
api='/collections/{collection_name}/index/{field_name}', | |
method="DELETE", | |
path_params={'collection_name': collection_name, 'field_name': 'country.capital'}, | |
query_params={'wait': 'true'}, | |
) | |
assert response.ok | |
response = request_with_validation( | |
api='/collections/{collection_name}/index/{field_name}', | |
method="DELETE", | |
path_params={'collection_name': collection_name, 'field_name': 'country.cities[].population'}, | |
query_params={'wait': 'true'}, | |
) | |
assert response.ok | |
response = request_with_validation( | |
api='/collections/{collection_name}', | |
method="GET", | |
path_params={'collection_name': collection_name}, | |
) | |
assert response.ok | |
assert len(response.json()['result']['payload_schema']) == 0 | |