// Copyright (C) 2019-2020 Zilliz. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software distributed under the License // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express // or implied. See the License for the specific language governing permissions and limitations under the License. #include #include #include #include #include "query/BinaryQuery.h" namespace milvus { namespace query { BinaryQueryPtr ConstructBinTree(std::vector queries, QueryRelation relation, uint64_t idx) { if (idx == queries.size()) { return nullptr; } else if (idx == queries.size() - 1) { return queries[idx]->getBinaryQuery(); } else { BinaryQueryPtr bquery = std::make_shared(); bquery->relation = relation; bquery->left_query = std::make_shared(); bquery->right_query = std::make_shared(); bquery->left_query->bin = queries[idx]->getBinaryQuery(); ++idx; bquery->right_query->bin = ConstructBinTree(queries, relation, idx); return bquery; } } Status ConstructLeafBinTree(std::vector leaf_queries, BinaryQueryPtr binary_query, uint64_t idx) { if (idx == leaf_queries.size()) { return Status::OK(); } binary_query->left_query = std::make_shared(); binary_query->right_query = std::make_shared(); if (leaf_queries.size() == leaf_queries.size() - 1) { binary_query->left_query->leaf = leaf_queries[idx]; return Status::OK(); } else if (idx == leaf_queries.size() - 2) { binary_query->left_query->leaf = leaf_queries[idx]; ++idx; binary_query->right_query->leaf = leaf_queries[idx]; return Status::OK(); } else { binary_query->left_query->bin->relation = binary_query->relation; binary_query->right_query->leaf = leaf_queries[idx]; ++idx; return ConstructLeafBinTree(leaf_queries, binary_query->left_query->bin, idx); } } Status GenBinaryQuery(BooleanQueryPtr query, BinaryQueryPtr& binary_query) { if (query->getBooleanQuerys().size() == 0) { if (binary_query->relation == QueryRelation::AND || binary_query->relation == QueryRelation::OR) { // Put VectorQuery to the end of leafqueries auto query_size = query->getLeafQueries().size(); for (uint64_t i = 0; i < query_size; ++i) { if (query->getLeafQueries()[i]->vector_query != nullptr) { std::swap(query->getLeafQueries()[i], query->getLeafQueries()[0]); break; } } return ConstructLeafBinTree(query->getLeafQueries(), binary_query, 0); } else { switch (query->getOccur()) { case Occur::MUST: { binary_query->relation = QueryRelation::AND; return GenBinaryQuery(query, binary_query); } case Occur::MUST_NOT: case Occur::SHOULD: { binary_query->relation = QueryRelation::OR; return GenBinaryQuery(query, binary_query); } default: return Status::OK(); } } } if (query->getBooleanQuerys().size() == 1) { auto bc = query->getBooleanQuerys()[0]; binary_query->left_query = std::make_shared(); switch (bc->getOccur()) { case Occur::MUST: { binary_query->relation = QueryRelation::AND; return GenBinaryQuery(bc, binary_query); } case Occur::MUST_NOT: case Occur::SHOULD: { binary_query->relation = QueryRelation::OR; return GenBinaryQuery(bc, binary_query); } default: return Status::OK(); } } // Construct binary query for every single boolean query std::vector must_queries; std::vector must_not_queries; std::vector should_queries; Status status; for (auto& _query : query->getBooleanQuerys()) { status = GenBinaryQuery(_query, _query->getBinaryQuery()); if (!status.ok()) { return status; } if (_query->getOccur() == Occur::MUST) { must_queries.emplace_back(_query); } else if (_query->getOccur() == Occur::MUST_NOT) { must_not_queries.emplace_back(_query); } else { should_queries.emplace_back(_query); } } // Construct binary query for combine boolean queries BinaryQueryPtr must_bquery, should_bquery, must_not_bquery; uint64_t bquery_num = 0; if (must_queries.size() > 1) { // Construct a must binary tree must_bquery = ConstructBinTree(must_queries, QueryRelation::R1, 0); ++bquery_num; } else if (must_queries.size() == 1) { must_bquery = must_queries[0]->getBinaryQuery(); ++bquery_num; } if (should_queries.size() > 1) { // Construct a should binary tree should_bquery = ConstructBinTree(should_queries, QueryRelation::R2, 0); ++bquery_num; } else if (should_queries.size() == 1) { should_bquery = should_queries[0]->getBinaryQuery(); ++bquery_num; } if (must_not_queries.size() > 1) { // Construct a must_not binary tree must_not_bquery = ConstructBinTree(must_not_queries, QueryRelation::R1, 0); ++bquery_num; } else if (must_not_queries.size() == 1) { must_not_bquery = must_not_queries[0]->getBinaryQuery(); ++bquery_num; } binary_query->left_query = std::make_shared(); binary_query->right_query = std::make_shared(); BinaryQueryPtr must_should_query = std::make_shared(); must_should_query->left_query = std::make_shared(); must_should_query->right_query = std::make_shared(); if (bquery_num == 3) { must_should_query->relation = QueryRelation::R3; must_should_query->left_query->bin = must_bquery; must_should_query->right_query->bin = should_bquery; binary_query->relation = QueryRelation::R1; binary_query->left_query->bin = must_should_query; binary_query->right_query->bin = must_not_bquery; } else if (bquery_num == 2) { if (must_bquery == nullptr) { binary_query->relation = QueryRelation::R3; binary_query->left_query->bin = must_not_bquery; binary_query->right_query->bin = should_bquery; } else if (should_bquery == nullptr) { binary_query->relation = QueryRelation::R4; binary_query->left_query->bin = must_bquery; binary_query->right_query->bin = must_not_bquery; } else { binary_query->relation = QueryRelation::R3; binary_query->left_query->bin = must_bquery; binary_query->right_query->bin = should_bquery; } } else { if (must_bquery != nullptr) { binary_query = must_bquery; } else if (should_bquery != nullptr) { binary_query = should_bquery; } else { binary_query = must_not_bquery; } } return Status::OK(); } uint64_t BinaryQueryHeight(BinaryQueryPtr& binary_query) { if (binary_query == nullptr) { return 1; } uint64_t left_height = 0, right_height = 0; if (binary_query->left_query != nullptr) { left_height = BinaryQueryHeight(binary_query->left_query->bin); } if (binary_query->right_query != nullptr) { right_height = BinaryQueryHeight(binary_query->right_query->bin); } return left_height > right_height ? left_height + 1 : right_height + 1; } bool ValidateBinaryQuery(BinaryQueryPtr& binary_query) { // Only for one layer BooleanQuery uint64_t height = BinaryQueryHeight(binary_query); return height > 1 && height < 4; } } // namespace query } // namespace milvus