milvus/core/src/query/BinaryQuery.cpp
zaqwsxqwer111 54fb8ef357
remove pragma once from .cpp files (#1982)
Signed-off-by: zaqwsxqwer111 <2536173042@qq.com>
2020-04-18 20:28:10 +08:00

221 lines
8.2 KiB
C++

// 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 <memory>
#include <string>
#include <utility>
#include <vector>
#include "query/BinaryQuery.h"
namespace milvus {
namespace query {
BinaryQueryPtr
ConstructBinTree(std::vector<BooleanQueryPtr> 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<BinaryQuery>();
bquery->relation = relation;
bquery->left_query = std::make_shared<GeneralQuery>();
bquery->right_query = std::make_shared<GeneralQuery>();
bquery->left_query->bin = queries[idx]->getBinaryQuery();
++idx;
bquery->right_query->bin = ConstructBinTree(queries, relation, idx);
return bquery;
}
}
Status
ConstructLeafBinTree(std::vector<LeafQueryPtr> leaf_queries, BinaryQueryPtr binary_query, uint64_t idx) {
if (idx == leaf_queries.size()) {
return Status::OK();
}
binary_query->left_query = std::make_shared<GeneralQuery>();
binary_query->right_query = std::make_shared<GeneralQuery>();
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);
}
}
}
}
if (query->getBooleanQuerys().size() == 1) {
auto bc = query->getBooleanQuerys()[0];
binary_query->left_query = std::make_shared<GeneralQuery>();
switch (bc->getOccur()) {
case Occur::MUST: {
binary_query->relation = QueryRelation::AND;
Status s = GenBinaryQuery(bc, binary_query);
return s;
}
case Occur::MUST_NOT:
case Occur::SHOULD: {
binary_query->relation = QueryRelation::OR;
Status s = GenBinaryQuery(bc, binary_query);
return s;
}
}
}
// Construct binary query for every single boolean query
std::vector<BooleanQueryPtr> must_queries;
std::vector<BooleanQueryPtr> must_not_queries;
std::vector<BooleanQueryPtr> 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<GeneralQuery>();
binary_query->right_query = std::make_shared<GeneralQuery>();
BinaryQueryPtr must_should_query = std::make_shared<BinaryQuery>();
must_should_query->left_query = std::make_shared<GeneralQuery>();
must_should_query->right_query = std::make_shared<GeneralQuery>();
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