fix: Fix exists expr for json flat index (#44910)

issue: https://github.com/milvus-io/milvus/issues/44915

Signed-off-by: sunby <sunbingyi1992@gmail.com>
This commit is contained in:
Bingyi Sun 2025-10-19 19:46:07 +08:00 committed by GitHub
parent 935160840c
commit 3ddf9154ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 21 additions and 37 deletions

View File

@ -98,7 +98,7 @@ PhyExistsFilterExpr::EvalJsonExistsForIndex() {
auto executor = auto executor =
json_flat_index->create_executor<double>(pointer); json_flat_index->create_executor<double>(pointer);
cached_index_chunk_res_ = std::make_shared<TargetBitmap>( cached_index_chunk_res_ = std::make_shared<TargetBitmap>(
std::move(executor->IsNotNull())); std::move(executor->Exists()));
break; break;
} }

View File

@ -34,7 +34,6 @@ JsonFlatIndex::build_index_for_json(
auto json = static_cast<const Json*>(data->RawValue(i)); auto json = static_cast<const Json*>(data->RawValue(i));
auto exists = path_exists(json->dom_doc(), tokens); auto exists = path_exists(json->dom_doc(), tokens);
if (!exists || !json->exist(nested_path_)) { if (!exists || !json->exist(nested_path_)) {
null_offset_.push_back(offset);
wrapper_->add_json_array_data(nullptr, 0, offset++); wrapper_->add_json_array_data(nullptr, 0, offset++);
continue; continue;
} }

View File

@ -22,15 +22,13 @@
#include "log/Log.h" #include "log/Log.h"
namespace milvus::index { namespace milvus::index {
class JsonFlatIndex;
// JsonFlatIndexQueryExecutor is used to execute queries on a specified json path, and can be constructed by JsonFlatIndex // JsonFlatIndexQueryExecutor is used to execute queries on a specified json path, and can be constructed by JsonFlatIndex
template <typename T> template <typename T>
class JsonFlatIndexQueryExecutor : public InvertedIndexTantivy<T> { class JsonFlatIndexQueryExecutor : public InvertedIndexTantivy<T> {
public: public:
JsonFlatIndexQueryExecutor(std::string& json_path, JsonFlatIndexQueryExecutor(std::string& json_path,
std::shared_ptr<TantivyIndexWrapper> wrapper) { const JsonFlatIndex& json_flat_index);
json_path_ = json_path;
this->wrapper_ = wrapper;
}
~JsonFlatIndexQueryExecutor() { ~JsonFlatIndexQueryExecutor() {
this->wrapper_ = nullptr; this->wrapper_ = nullptr;
@ -47,19 +45,9 @@ class JsonFlatIndexQueryExecutor : public InvertedIndexTantivy<T> {
return bitset; return bitset;
} }
const TargetBitmap
IsNull() override {
tracer::AutoSpan span("JsonFlatIndexQueryExecutor::IsNull",
tracer::GetRootSpan());
TargetBitmap bitset(this->Count());
this->wrapper_->json_exist_query(json_path_, &bitset);
bitset.flip();
return bitset;
}
TargetBitmap TargetBitmap
IsNotNull() override { Exists() {
tracer::AutoSpan span("JsonFlatIndexQueryExecutor::IsNotNull", tracer::AutoSpan span("JsonFlatIndexQueryExecutor::Exists",
tracer::GetRootSpan()); tracer::GetRootSpan());
TargetBitmap bitset(this->Count()); TargetBitmap bitset(this->Count());
this->wrapper_->json_exist_query(json_path_, &bitset); this->wrapper_->json_exist_query(json_path_, &bitset);
@ -107,7 +95,7 @@ class JsonFlatIndexQueryExecutor : public InvertedIndexTantivy<T> {
bitset.flip(); bitset.flip();
// TODO: optimize this // TODO: optimize this
auto null_bitset = IsNotNull(); auto null_bitset = this->IsNotNull();
bitset &= null_bitset; bitset &= null_bitset;
return bitset; return bitset;
@ -194,6 +182,9 @@ class JsonFlatIndexQueryExecutor : public InvertedIndexTantivy<T> {
// we need to reuse InvertedIndexTantivy's Build and Load implementation, so we specify the template parameter as std::string // we need to reuse InvertedIndexTantivy's Build and Load implementation, so we specify the template parameter as std::string
// JsonFlatIndex should not be used to execute queries, use JsonFlatIndexQueryExecutor instead // JsonFlatIndex should not be used to execute queries, use JsonFlatIndexQueryExecutor instead
class JsonFlatIndex : public InvertedIndexTantivy<std::string> { class JsonFlatIndex : public InvertedIndexTantivy<std::string> {
template <typename T>
friend class JsonFlatIndexQueryExecutor;
public: public:
JsonFlatIndex() : InvertedIndexTantivy<std::string>() { JsonFlatIndex() : InvertedIndexTantivy<std::string>() {
} }
@ -224,7 +215,7 @@ class JsonFlatIndex : public InvertedIndexTantivy<std::string> {
json_path); json_path);
return std::make_shared<JsonFlatIndexQueryExecutor<T>>(json_path, return std::make_shared<JsonFlatIndexQueryExecutor<T>>(json_path,
this->wrapper_); *this);
} }
JsonCastType JsonCastType
@ -250,4 +241,12 @@ class JsonFlatIndex : public InvertedIndexTantivy<std::string> {
private: private:
std::string nested_path_; std::string nested_path_;
}; };
template <typename T>
JsonFlatIndexQueryExecutor<T>::JsonFlatIndexQueryExecutor(
std::string& json_path, const JsonFlatIndex& json_flat_index) {
json_path_ = json_path;
this->wrapper_ = json_flat_index.wrapper_;
this->null_offset_ = json_flat_index.null_offset_;
}
} // namespace milvus::index } // namespace milvus::index

View File

@ -193,30 +193,16 @@ TEST_F(JsonFlatIndexTest, TestInQuery) {
ASSERT_FALSE(result[2]); // Charlie ASSERT_FALSE(result[2]); // Charlie
} }
TEST_F(JsonFlatIndexTest, TestIsNullQuery) { TEST_F(JsonFlatIndexTest, TestExistsQuery) {
auto json_flat_index = auto json_flat_index =
dynamic_cast<index::JsonFlatIndex*>(json_index_.get()); dynamic_cast<index::JsonFlatIndex*>(json_index_.get());
ASSERT_NE(json_flat_index, nullptr); ASSERT_NE(json_flat_index, nullptr);
std::string json_path = "/profile/name/preferred_name"; std::string json_path = "/profile/name/preferred_name";
auto executor = json_flat_index->create_executor<std::string>(json_path); auto executor = json_flat_index->create_executor<std::string>(json_path);
auto result = executor->IsNull(); auto result = executor->Exists();
ASSERT_EQ(result.size(), json_data_.size()); ASSERT_EQ(result.size(), json_data_.size());
ASSERT_FALSE(result[0]); // Al ASSERT_TRUE(result[0]); // Alice
ASSERT_TRUE(result[1]); // null
ASSERT_TRUE(result[2]); // not exist
}
TEST_F(JsonFlatIndexTest, TestIsNotNullQuery) {
auto json_flat_index =
dynamic_cast<index::JsonFlatIndex*>(json_index_.get());
ASSERT_NE(json_flat_index, nullptr);
std::string json_path = "/profile/name/preferred_name";
auto executor = json_flat_index->create_executor<std::string>(json_path);
auto result = executor->IsNotNull();
ASSERT_EQ(result.size(), json_data_.size());
ASSERT_TRUE(result[0]); // Al
ASSERT_FALSE(result[1]); // null ASSERT_FALSE(result[1]); // null
ASSERT_FALSE(result[2]); // not exist ASSERT_FALSE(result[2]); // not exist
} }