From 3ddf9154abdc5997f31d6f064dce0b66585b7d7a Mon Sep 17 00:00:00 2001 From: Bingyi Sun Date: Sun, 19 Oct 2025 19:46:07 +0800 Subject: [PATCH] fix: Fix exists expr for json flat index (#44910) issue: https://github.com/milvus-io/milvus/issues/44915 Signed-off-by: sunby --- .../core/src/exec/expression/ExistsExpr.cpp | 2 +- internal/core/src/index/JsonFlatIndex.cpp | 1 - internal/core/src/index/JsonFlatIndex.h | 35 +++++++++---------- internal/core/src/index/JsonFlatIndexTest.cpp | 20 ++--------- 4 files changed, 21 insertions(+), 37 deletions(-) diff --git a/internal/core/src/exec/expression/ExistsExpr.cpp b/internal/core/src/exec/expression/ExistsExpr.cpp index 60f411e361..a1c8bfb297 100644 --- a/internal/core/src/exec/expression/ExistsExpr.cpp +++ b/internal/core/src/exec/expression/ExistsExpr.cpp @@ -98,7 +98,7 @@ PhyExistsFilterExpr::EvalJsonExistsForIndex() { auto executor = json_flat_index->create_executor(pointer); cached_index_chunk_res_ = std::make_shared( - std::move(executor->IsNotNull())); + std::move(executor->Exists())); break; } diff --git a/internal/core/src/index/JsonFlatIndex.cpp b/internal/core/src/index/JsonFlatIndex.cpp index 445be22dfd..cd2a1dd847 100644 --- a/internal/core/src/index/JsonFlatIndex.cpp +++ b/internal/core/src/index/JsonFlatIndex.cpp @@ -34,7 +34,6 @@ JsonFlatIndex::build_index_for_json( auto json = static_cast(data->RawValue(i)); auto exists = path_exists(json->dom_doc(), tokens); if (!exists || !json->exist(nested_path_)) { - null_offset_.push_back(offset); wrapper_->add_json_array_data(nullptr, 0, offset++); continue; } diff --git a/internal/core/src/index/JsonFlatIndex.h b/internal/core/src/index/JsonFlatIndex.h index 706bf0a08f..7124213f8f 100644 --- a/internal/core/src/index/JsonFlatIndex.h +++ b/internal/core/src/index/JsonFlatIndex.h @@ -22,15 +22,13 @@ #include "log/Log.h" namespace milvus::index { +class JsonFlatIndex; // JsonFlatIndexQueryExecutor is used to execute queries on a specified json path, and can be constructed by JsonFlatIndex template class JsonFlatIndexQueryExecutor : public InvertedIndexTantivy { public: JsonFlatIndexQueryExecutor(std::string& json_path, - std::shared_ptr wrapper) { - json_path_ = json_path; - this->wrapper_ = wrapper; - } + const JsonFlatIndex& json_flat_index); ~JsonFlatIndexQueryExecutor() { this->wrapper_ = nullptr; @@ -47,19 +45,9 @@ class JsonFlatIndexQueryExecutor : public InvertedIndexTantivy { 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 - IsNotNull() override { - tracer::AutoSpan span("JsonFlatIndexQueryExecutor::IsNotNull", + Exists() { + tracer::AutoSpan span("JsonFlatIndexQueryExecutor::Exists", tracer::GetRootSpan()); TargetBitmap bitset(this->Count()); this->wrapper_->json_exist_query(json_path_, &bitset); @@ -107,7 +95,7 @@ class JsonFlatIndexQueryExecutor : public InvertedIndexTantivy { bitset.flip(); // TODO: optimize this - auto null_bitset = IsNotNull(); + auto null_bitset = this->IsNotNull(); bitset &= null_bitset; return bitset; @@ -194,6 +182,9 @@ class JsonFlatIndexQueryExecutor : public InvertedIndexTantivy { // 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 class JsonFlatIndex : public InvertedIndexTantivy { + template + friend class JsonFlatIndexQueryExecutor; + public: JsonFlatIndex() : InvertedIndexTantivy() { } @@ -224,7 +215,7 @@ class JsonFlatIndex : public InvertedIndexTantivy { json_path); return std::make_shared>(json_path, - this->wrapper_); + *this); } JsonCastType @@ -250,4 +241,12 @@ class JsonFlatIndex : public InvertedIndexTantivy { private: std::string nested_path_; }; + +template +JsonFlatIndexQueryExecutor::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 \ No newline at end of file diff --git a/internal/core/src/index/JsonFlatIndexTest.cpp b/internal/core/src/index/JsonFlatIndexTest.cpp index 4c4840e337..2d06de710f 100644 --- a/internal/core/src/index/JsonFlatIndexTest.cpp +++ b/internal/core/src/index/JsonFlatIndexTest.cpp @@ -193,30 +193,16 @@ TEST_F(JsonFlatIndexTest, TestInQuery) { ASSERT_FALSE(result[2]); // Charlie } -TEST_F(JsonFlatIndexTest, TestIsNullQuery) { +TEST_F(JsonFlatIndexTest, TestExistsQuery) { auto json_flat_index = dynamic_cast(json_index_.get()); ASSERT_NE(json_flat_index, nullptr); std::string json_path = "/profile/name/preferred_name"; auto executor = json_flat_index->create_executor(json_path); - auto result = executor->IsNull(); + auto result = executor->Exists(); ASSERT_EQ(result.size(), json_data_.size()); - ASSERT_FALSE(result[0]); // Al - ASSERT_TRUE(result[1]); // null - ASSERT_TRUE(result[2]); // not exist -} - -TEST_F(JsonFlatIndexTest, TestIsNotNullQuery) { - auto json_flat_index = - dynamic_cast(json_index_.get()); - ASSERT_NE(json_flat_index, nullptr); - - std::string json_path = "/profile/name/preferred_name"; - auto executor = json_flat_index->create_executor(json_path); - auto result = executor->IsNotNull(); - ASSERT_EQ(result.size(), json_data_.size()); - ASSERT_TRUE(result[0]); // Al + ASSERT_TRUE(result[0]); // Alice ASSERT_FALSE(result[1]); // null ASSERT_FALSE(result[2]); // not exist }