diff --git a/tests/milvus_python_test/entity/test_search.py b/tests/milvus_python_test/entity/test_search.py index 16becc977b64a7d6a6f74013f12a3486960c4698..bf43f1a145d785492cd32d09e3914a72a6e0a538 100644 --- a/tests/milvus_python_test/entity/test_search.py +++ b/tests/milvus_python_test/entity/test_search.py @@ -877,7 +877,7 @@ class TestSearchDSL(object): def test_query_no_vector_term_only(self, connect, collection): ''' - method: build query without must expr + method: build query without vector only term expected: error raised ''' # entities, ids = init_data(connect, collection) @@ -888,6 +888,19 @@ class TestSearchDSL(object): with pytest.raises(Exception) as e: res = connect.search(collection, query) + def test_query_no_vector_range_only(self, connect, collection): + ''' + method: build query without vector only range + expected: error raised + ''' + # entities, ids = init_data(connect, collection) + expr = { + "must": [gen_default_range_expr] + } + query = update_query_expr(default_query, keep_old=False, expr=expr) + with pytest.raises(Exception) as e: + res = connect.search(collection, query) + def test_query_vector_only(self, connect, collection): entities, ids = init_data(connect, collection) res = connect.search(collection, default_query) @@ -1087,6 +1100,21 @@ class TestSearchDSL(object): assert len(res[0]) == top_k connect.drop_collection(collection_term) + @pytest.mark.level(2) + def test_query_term_one_field_not_existed(self, connect, collection): + ''' + method: build query with two fields term, one of it not existed + expected: exception raised + ''' + entities, ids = init_data(connect, collection) + term = gen_default_term_expr() + term["term"].update({"a": [0]}) + expr = {"must": [gen_default_vector_expr(default_query), term]} + query = update_query_expr(default_query, expr=expr) + logging.getLogger().info(query) + with pytest.raises(Exception) as e: + res = connect.search(collection, query) + """ ****************************************************************** # The following cases are used to build valid range query expr @@ -1126,6 +1154,28 @@ class TestSearchDSL(object): with pytest.raises(Exception) as e: res = connect.search(collection, query) + @pytest.fixture( + scope="function", + params=gen_invalid_ranges() + ) + def get_invalid_ranges(self, request): + return request.param + + @pytest.mark.level(2) + def test_query_range_invalid_ranges(self, connect, collection, get_invalid_ranges): + ''' + method: build query with invalid ranges + expected: raise Exception + ''' + entities, ids = init_data(connect, collection) + ranges = get_invalid_ranges + range = gen_default_range_expr(ranges=ranges) + expr = {"must": [gen_default_vector_expr(default_query), range]} + query = update_query_expr(default_query, expr=expr) + logging.getLogger().info(query) + with pytest.raises(Exception) as e: + res = connect.search(collection, query) + @pytest.fixture( scope="function", params=gen_valid_ranges() @@ -1134,6 +1184,7 @@ class TestSearchDSL(object): return request.param # TODO: + @pytest.mark.level(2) def test_query_range_valid_ranges(self, connect, collection, get_valid_ranges): ''' method: build query with valid ranges @@ -1144,10 +1195,220 @@ class TestSearchDSL(object): range = gen_default_range_expr(ranges=ranges) expr = {"must": [gen_default_vector_expr(default_query), range]} query = update_query_expr(default_query, expr=expr) + logging.getLogger().info(query) + res = connect.search(collection, query) + assert len(res) == nq + assert len(res[0]) == top_k + + def test_query_range_one_field_not_existed(self, connect, collection): + ''' + method: build query with two fields ranges, one of fields not existed + expected: exception raised + ''' + entities, ids = init_data(connect, collection) + range = gen_default_range_expr() + range["range"].update({"a": {"GT": 1, "LT": nb // 2}}) + expr = {"must": [gen_default_vector_expr(default_query), range]} + query = update_query_expr(default_query, expr=expr) + with pytest.raises(Exception) as e: + res = connect.search(collection, query) + + """ + ************************************************************************ + # The following cases are used to build query expr multi range and term + ************************************************************************ + """ + + # TODO + @pytest.mark.level(2) + def test_query_multi_term_has_common(self, connect, collection): + ''' + method: build query with multi term with same field, and values has common + expected: pass + ''' + entities, ids = init_data(connect, collection) + term_first = gen_default_term_expr() + term_second = gen_default_term_expr(values=[i for i in range(nb // 3)]) + expr = {"must": [gen_default_vector_expr(default_query), term_first, term_second]} + query = update_query_expr(default_query, expr=expr) + res = connect.search(collection, query) + assert len(res) == nq + assert len(res[0]) == top_k + + # TODO + @pytest.mark.level(2) + def test_query_multi_term_no_common(self, connect, collection): + ''' + method: build query with multi range with same field, and ranges no common + expected: pass + ''' + entities, ids = init_data(connect, collection) + term_first = gen_default_term_expr() + term_second = gen_default_term_expr(values=[i for i in range(nb // 2, nb + nb // 2)]) + expr = {"must": [gen_default_vector_expr(default_query), term_first, term_second]} + query = update_query_expr(default_query, expr=expr) + res = connect.search(collection, query) + assert len(res) == nq + assert len(res[0]) == 0 + + # TODO + def test_query_multi_term_different_fields(self, connect, collection): + ''' + method: build query with multi range with same field, and ranges no common + expected: pass + ''' + entities, ids = init_data(connect, collection) + term_first = gen_default_term_expr() + term_second = gen_default_term_expr(field="float", values=[float(i) for i in range(nb//2, nb)]) + expr = {"must": [gen_default_vector_expr(default_query), term_first, term_second]} + query = update_query_expr(default_query, expr=expr) + res = connect.search(collection, query) + assert len(res) == nq + assert len(res[0]) == 0 + + # TODO + @pytest.mark.level(2) + def test_query_single_term_multi_fields(self, connect, collection): + ''' + method: build query with multi term, different field each term + expected: pass + ''' + entities, ids = init_data(connect, collection) + term_first = {"int64": {"values": [i for i in range(nb//2)]}} + term_second = {"float": {"values": [float(i) for i in range(nb//2, nb)]}} + term = update_term_expr({"term": {}}, [term_first, term_second]) + expr = {"must": [gen_default_vector_expr(default_query), term]} + query = update_query_expr(default_query, expr=expr) + logging.getLogger().info(query) + res = connect.search(collection, query) + assert len(res) == nq + assert len(res[0]) == 0 + + # TODO + @pytest.mark.level(2) + def test_query_multi_range_has_common(self, connect, collection): + ''' + method: build query with multi range with same field, and ranges has common + expected: pass + ''' + entities, ids = init_data(connect, collection) + range_one = gen_default_range_expr() + range_two = gen_default_range_expr(ranges={"GT": 1, "LT": nb // 3}) + expr = {"must": [gen_default_vector_expr(default_query), range_one, range_two]} + query = update_query_expr(default_query, expr=expr) + res = connect.search(collection, query) + assert len(res) == nq + assert len(res[0]) == top_k + + # TODO + @pytest.mark.level(2) + def test_query_multi_range_no_common(self, connect, collection): + ''' + method: build query with multi range with same field, and ranges no common + expected: pass + ''' + entities, ids = init_data(connect, collection) + range_one = gen_default_range_expr() + range_two = gen_default_range_expr(ranges={"GT": nb // 2, "LT": nb}) + expr = {"must": [gen_default_vector_expr(default_query), range_one, range_two]} + query = update_query_expr(default_query, expr=expr) + res = connect.search(collection, query) + assert len(res) == nq + assert len(res[0]) == 0 + + # TODO + @pytest.mark.level(2) + def test_query_multi_range_different_fields(self, connect, collection): + ''' + method: build query with multi range, different field each range + expected: pass + ''' + entities, ids = init_data(connect, collection) + range_first = gen_default_range_expr() + range_second = gen_default_range_expr(field="float", ranges={"GT": nb // 2, "LT": nb}) + expr = {"must": [gen_default_vector_expr(default_query), range_first, range_second]} + query = update_query_expr(default_query, expr=expr) + logging.getLogger().info(query) + res = connect.search(collection, query) + assert len(res) == nq + assert len(res[0]) == 0 + + # TODO + @pytest.mark.level(2) + def test_query_single_range_multi_fields(self, connect, collection): + ''' + method: build query with multi range, different field each range + expected: pass + ''' + entities, ids = init_data(connect, collection) + range_first = {"int64": {"GT": 0, "LT": nb // 2}} + range_second = {"float": {"GT": nb / 2, "LT": float(nb)}} + range = update_range_expr({"range": {}}, [range_first, range_second]) + expr = {"must": [gen_default_vector_expr(default_query), range]} + query = update_query_expr(default_query, expr=expr) + logging.getLogger().info(query) + res = connect.search(collection, query) + assert len(res) == nq + assert len(res[0]) == 0 + + """ + ****************************************************************** + # The following cases are used to build query expr both term and range + ****************************************************************** + """ + + # TODO + @pytest.mark.level(2) + def test_query_single_term_range_has_common(self, connect, collection): + ''' + method: build query with single term single range + expected: pass + ''' + term = gen_default_term_expr() + range = gen_default_range_expr(ranges={"GT": -1, "LT": nb//2}) + expr = {"must": [gen_default_vector_expr(default_query), term, range]} + query = update_query_expr(default_query, expr=expr) res = connect.search(collection, query) assert len(res) == nq assert len(res[0]) == top_k + # TODO + def test_query_single_term_range_no_common(self, connect, collection): + ''' + method: build query with single term single range + expected: pass + ''' + term = gen_default_term_expr() + range = gen_default_range_expr(ranges={"GT": nb // 2, "LT": nb}) + expr = {"must": [gen_default_vector_expr(default_query), term, range]} + query = update_query_expr(default_query, expr=expr) + res = connect.search(collection, query) + assert len(res) == nq + assert len(res[0]) == 0 + + + """ + ****************************************************************** + # The following cases are used to build multi vectors query expr + ****************************************************************** + """ + + # TODO + def test_query_multi_vectors_same_field(self, connect, collection): + ''' + method: build query with two vectors same field + expected: error raised + ''' + entities, ids = init_data(connect, collection) + vector1 = default_query + vector2 = gen_query_vectors(field_name, entities, top_k, nq=2) + expr = { + "must": [vector1, vector2] + } + query = update_query_expr(default_query, expr=expr) + with pytest.raises(Exception) as e: + res = connect.search(collection, query) + class TestSearchDSLBools(object): """ @@ -1156,12 +1417,14 @@ class TestSearchDSLBools(object): ****************************************************************** """ + @pytest.mark.level(2) def test_query_no_bool(self, connect, collection): ''' method: build query without bool expr expected: error raised ''' expr = {"bool1": {}} + query = expr with pytest.raises(Exception) as e: res = connect.search(collection, query) diff --git a/tests/milvus_python_test/utils.py b/tests/milvus_python_test/utils.py index dd85f64028aefb464e791fe6e28c2e6105d60fef..d0ebf5b0770d3dec15f9742d15e3bc8a7e8de39b 100644 --- a/tests/milvus_python_test/utils.py +++ b/tests/milvus_python_test/utils.py @@ -304,26 +304,40 @@ def gen_default_vector_expr(default_query): return default_query["bool"]["must"][0] -def gen_default_term_expr(keyword="term", values=None): +def gen_default_term_expr(keyword="term", field="int64", values=None): if values is None: values = [i for i in range(nb // 2)] - expr = {keyword: {"int64": {"values": values}}} + expr = {keyword: {field: {"values": values}}} return expr -def gen_default_range_expr(keyword="range", ranges=None): +def update_term_expr(src_term, terms): + tmp_term = copy.deepcopy(src_term) + for term in terms: + tmp_term["term"].update(term) + return tmp_term + + +def gen_default_range_expr(keyword="range", field="int64", ranges=None): if ranges is None: ranges = {"GT": 1, "LT": nb // 2} - expr = {keyword: {"int64": ranges}} + expr = {keyword: {field: ranges}} return expr +def update_range_expr(src_range, ranges): + tmp_range = copy.deepcopy(src_range) + for range in ranges: + tmp_range["range"].update(range) + return tmp_range + + def gen_invalid_range(): range = [ {"range": 1}, {"range": {}}, {"range": []}, - {"range": {"range": {"int64": {"ranges": {"GT": 0, "LT": nb//2}}}}} + {"range": {"range": {"int64": {"GT": 0, "LT": nb // 2}}}} ] return range @@ -331,9 +345,7 @@ def gen_invalid_range(): def gen_invalid_ranges(): ranges = [ {"GT": nb, "LT": 0}, - {"GT": nb}, - {"LT": 0}, - {"GT": 0.0, "LT": float(nb)} + {"GT": "0", "LT": "1000"} ] return ranges @@ -353,7 +365,8 @@ def gen_invalid_term(): terms = [ {"term": 1}, {"term": []}, - {"term": {"term": {"int64": {"values": [i for i in range(nb//2)]}}}} + {"term": {}}, + {"term": {"term": {"int64": {"values": [i for i in range(nb // 2)]}}}} ] return terms