diff options
author | Henning Baldersheim <balder@yahoo-inc.com> | 2024-04-25 16:26:29 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-25 16:26:29 +0200 |
commit | 16ac700c95696e3c22c123816428ac877a86f233 (patch) | |
tree | 7e8e7189bde358e4e650b351e99eb6fa7c4b791d | |
parent | cccd53e6df76e2abc9adf9a7f8cc47cff17ef736 (diff) | |
parent | e9c1e954efcc991ac9b0ada1be3d908b5cfa1905 (diff) |
Merge pull request #31046 from vespa-engine/balder/use-non_existing_attibute_value-flag
Use non_existing_attribute_value to signal that value is the default … MERGEOK
7 files changed, 116 insertions, 113 deletions
diff --git a/eval/src/tests/eval/typed_cells/typed_cells_test.cpp b/eval/src/tests/eval/typed_cells/typed_cells_test.cpp index f4171937ce3..53e0f7c84d3 100644 --- a/eval/src/tests/eval/typed_cells/typed_cells_test.cpp +++ b/eval/src/tests/eval/typed_cells/typed_cells_test.cpp @@ -1,39 +1,13 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/eval/eval/typed_cells.h> #include <vespa/vespalib/testkit/test_kit.h> -#include <vespa/vespalib/util/arrayref.h> #include <memory> using namespace vespalib; +using namespace eval; -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -// Low-level typed cells reference -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -enum class CellType : char { DOUBLE, FLOAT, INT }; -template <typename T> bool check_type(CellType type); -template <> bool check_type<double>(CellType type) { return (type == CellType::DOUBLE); } -template <> bool check_type<float>(CellType type) { return (type == CellType::FLOAT); } -template <> bool check_type<int>(CellType type) { return (type == CellType::INT); } - -struct TypedCells { - const void *data; - CellType type; - size_t size:56; - explicit TypedCells(ConstArrayRef<double> cells) : data(cells.begin()), type(CellType::DOUBLE), size(cells.size()) {} - explicit TypedCells(ConstArrayRef<float> cells) : data(cells.begin()), type(CellType::FLOAT), size(cells.size()) {} - explicit TypedCells(ConstArrayRef<int> cells) : data(cells.begin()), type(CellType::INT), size(cells.size()) {} - template <typename T> bool check_type() const { return ::check_type<T>(type); } - template <typename T> ConstArrayRef<T> typify() const { - assert(check_type<T>()); - return ConstArrayRef<T>((const T *)data, size); - } - template <typename T> ConstArrayRef<T> unsafe_typify() const { - return ConstArrayRef<T>((const T *)data, size); - } -}; TEST("require that structures are of expected size") { EXPECT_EQUAL(sizeof(void*), 8u); @@ -102,27 +76,27 @@ struct Typify { switch(a.type) { case CellType::DOUBLE: return T::call(a.unsafe_typify<double>(), std::forward<Args>(args)...); case CellType::FLOAT: return T::call(a.unsafe_typify<float>(), std::forward<Args>(args)...); - case CellType::INT: return T::call(a.unsafe_typify<int>(), std::forward<Args>(args)...); + case CellType::INT8: return T::call(a.unsafe_typify<Int8Float>(), std::forward<Args>(args)...); + default: abort(); } - abort(); } template <typename A, typename... Args> static auto typify_2(A &&a, const TypedCells &b, Args &&...args) { switch(b.type) { case CellType::DOUBLE: return T::call(std::forward<A>(a), b.unsafe_typify<double>(), std::forward<Args>(args)...); case CellType::FLOAT: return T::call(std::forward<A>(a), b.unsafe_typify<float>(), std::forward<Args>(args)...); - case CellType::INT: return T::call(std::forward<A>(a), b.unsafe_typify<int>(), std::forward<Args>(args)...); + case CellType::INT8: return T::call(std::forward<A>(a), b.unsafe_typify<Int8Float>(), std::forward<Args>(args)...); + default: abort(); } - abort(); } template <typename A, typename B, typename... Args> static auto typify_3(A &&a, B &&b, const TypedCells &c, Args &&...args) { switch(c.type) { case CellType::DOUBLE: return T::call(std::forward<A>(a), std::forward<B>(b), c.unsafe_typify<double>(), std::forward<Args>(args)...); case CellType::FLOAT: return T::call(std::forward<A>(a), std::forward<B>(b), c.unsafe_typify<float>(), std::forward<Args>(args)...); - case CellType::INT: return T::call(std::forward<A>(a), std::forward<B>(b), c.unsafe_typify<int>(), std::forward<Args>(args)...); + case CellType::INT8: return T::call(std::forward<A>(a), std::forward<B>(b), c.unsafe_typify<Int8Float>(), std::forward<Args>(args)...); + default: abort(); } - abort(); } }; @@ -200,15 +174,15 @@ struct Dispatch1 { //----------------------------------------------------------------------------- TEST("require that direct dispatch 'a op b -> c' works") { - std::vector<int> a({1,2,3}); - std::vector<float> b({1.5,2.5,3.5}); - std::vector<double> c(3, 0.0); - ConstArrayRef<int> a_ref(a); - ConstArrayRef<float> b_ref(b); - ConstArrayRef<double> c_ref(c); - TypedCells a_cells(a); - TypedCells b_cells(b); - TypedCells c_cells(c); + std::vector<Int8Float> a({1,2,3}); + std::vector<float> b({1.5,2.5,3.5}); + std::vector<double> c(3, 0.0); + ConstArrayRef<Int8Float> a_ref(a); + ConstArrayRef<float> b_ref(b); + ConstArrayRef<double> c_ref(c); + TypedCells a_cells(a); + TypedCells b_cells(b); + TypedCells c_cells(c); Dispatch3<CellwiseAdd>::call(a_cells, b_cells, c_cells, 3); Dispatch3<CellwiseAdd>::call(a_cells, b_ref, c_cells, 3); @@ -225,13 +199,13 @@ TEST("require that direct dispatch 'a op b -> c' works") { } TEST("require that direct dispatch 'dot product' with return value works") { - std::vector<int> a({1,2,3}); - std::vector<float> b({1.5,2.5,3.5}); - ConstArrayRef<int> a_ref(a); - ConstArrayRef<float> b_ref(b); - TypedCells a_cells(a); - TypedCells b_cells(b); - double expect = 1.5 + (2 * 2.5) + (3 * 3.5); + std::vector<Int8Float> a({1,2,3}); + std::vector<float> b({1.5,2.5,3.5}); + ConstArrayRef<Int8Float> a_ref(a); + ConstArrayRef<float> b_ref(b); + TypedCells a_cells(a); + TypedCells b_cells(b); + double expect = 1.5 + (2 * 2.5) + (3 * 3.5); EXPECT_EQUAL(expect, Dispatch2<DotProduct>::call(a_cells, b_cells, 3)); EXPECT_EQUAL(expect, Dispatch2<DotProduct>::call(a_cells, b_ref, 3)); @@ -240,10 +214,10 @@ TEST("require that direct dispatch 'dot product' with return value works") { } TEST("require that direct dispatch 'sum' with return value works") { - std::vector<int> a({1,2,3}); - ConstArrayRef<int> a_ref(a); - TypedCells a_cells(a); - double expect = (1 + 2 + 3); + std::vector<Int8Float> a({1,2,3}); + ConstArrayRef<Int8Float> a_ref(a); + TypedCells a_cells(a); + double expect = (1 + 2 + 3); EXPECT_EQUAL(expect, Dispatch1<Sum>::call(a_cells)); EXPECT_EQUAL(expect, Dispatch1<Sum>::call(a_ref)); @@ -259,7 +233,7 @@ struct CellwiseAdd2 { virtual void call(const TypedCells &a, const TypedCells &b, const TypedCells &c, size_t cnt) const = 0; template <typename A, typename B, typename C> static std::unique_ptr<CellwiseAdd2> create(); - virtual ~CellwiseAdd2() {} + virtual ~CellwiseAdd2() = default; }; template <typename A, typename B, typename C> @@ -286,7 +260,7 @@ struct DotProduct2 { virtual double call(const TypedCells &a, const TypedCells &b, size_t cnt) const = 0; template <typename A, typename B> static std::unique_ptr<DotProduct2> create(); - virtual ~DotProduct2() {} + virtual ~DotProduct2() = default; }; template <typename A, typename B> @@ -314,7 +288,7 @@ struct Sum2 { virtual double call(const TypedCells &a) const = 0; template <typename A> static std::unique_ptr<Sum2> create(); - virtual ~Sum2() {} + virtual ~Sum2() = default; }; template <typename A> @@ -343,9 +317,9 @@ std::unique_ptr<T> create(CellType a_type) { switch(a_type) { case CellType::DOUBLE: return T::template create<double, Args...>(); case CellType::FLOAT: return T::template create<float, Args...>(); - case CellType::INT: return T::template create<int, Args...>(); + case CellType::INT8: return T::template create<Int8Float, Args...>(); + default: abort(); } - abort(); } template <typename T, typename... Args> @@ -353,9 +327,9 @@ std::unique_ptr<T> create(CellType a_type, CellType b_type) { switch(b_type) { case CellType::DOUBLE: return create<T, double, Args...>(a_type); case CellType::FLOAT: return create<T, float, Args...>(a_type); - case CellType::INT: return create<T, int, Args...>(a_type); + case CellType::INT8: return create<T, Int8Float, Args...>(a_type); + default: abort(); } - abort(); } template <typename T> @@ -363,20 +337,20 @@ std::unique_ptr<T> create(CellType a_type, CellType b_type, CellType c_type) { switch(c_type) { case CellType::DOUBLE: return create<T, double>(a_type, b_type); case CellType::FLOAT: return create<T, float>(a_type, b_type); - case CellType::INT: return create<T, int>(a_type, b_type); + case CellType::INT8: return create<T, Int8Float>(a_type, b_type); + default: abort(); } - abort(); } //----------------------------------------------------------------------------- TEST("require that pre-resolved subclass 'a op b -> c' works") { - std::vector<int> a({1,2,3}); - std::vector<float> b({1.5,2.5,3.5}); - std::vector<double> c(3, 0.0); - TypedCells a_cells(a); - TypedCells b_cells(b); - TypedCells c_cells(c); + std::vector<Int8Float> a({1,2,3}); + std::vector<float> b({1.5,2.5,3.5}); + std::vector<double> c(3, 0.0); + TypedCells a_cells(a); + TypedCells b_cells(b); + TypedCells c_cells(c); auto op = create<CellwiseAdd2>(a_cells.type, b_cells.type, c_cells.type); op->call(a_cells, b_cells, c_cells, 3); @@ -387,11 +361,11 @@ TEST("require that pre-resolved subclass 'a op b -> c' works") { } TEST("require that pre-resolved subclass 'dot product' with return value works") { - std::vector<int> a({1,2,3}); - std::vector<float> b({1.5,2.5,3.5}); - TypedCells a_cells(a); - TypedCells b_cells(b); - double expect = 1.5 + (2 * 2.5) + (3 * 3.5); + std::vector<Int8Float> a({1,2,3}); + std::vector<float> b({1.5,2.5,3.5}); + TypedCells a_cells(a); + TypedCells b_cells(b); + double expect = 1.5 + (2 * 2.5) + (3 * 3.5); auto op = create<DotProduct2>(a_cells.type, b_cells.type); @@ -399,9 +373,9 @@ TEST("require that pre-resolved subclass 'dot product' with return value works") } TEST("require that pre-resolved subclass 'sum' with return value works") { - std::vector<int> a({1,2,3}); - TypedCells a_cells(a); - double expect = (1 + 2 + 3); + std::vector<Int8Float> a({1,2,3}); + TypedCells a_cells(a); + double expect = (1 + 2 + 3); auto op = create<Sum2>(a_cells.type); @@ -419,9 +393,9 @@ auto get_fun(CellType a_type) { switch(a_type) { case CellType::DOUBLE: return T::template get_fun<double, Args...>(); case CellType::FLOAT: return T::template get_fun<float, Args...>(); - case CellType::INT: return T::template get_fun<int, Args...>(); + case CellType::INT8: return T::template get_fun<Int8Float, Args...>(); + default: abort(); } - abort(); } template <typename T, typename... Args> @@ -429,9 +403,9 @@ auto get_fun(CellType a_type, CellType b_type) { switch(b_type) { case CellType::DOUBLE: return get_fun<T, double, Args...>(a_type); case CellType::FLOAT: return get_fun<T, float, Args...>(a_type); - case CellType::INT: return get_fun<T, int, Args...>(a_type); + case CellType::INT8: return get_fun<T, Int8Float, Args...>(a_type); + default: abort(); } - abort(); } template <typename T> @@ -439,9 +413,9 @@ auto get_fun(CellType a_type, CellType b_type, CellType c_type) { switch(c_type) { case CellType::DOUBLE: return get_fun<T, double>(a_type, b_type); case CellType::FLOAT: return get_fun<T, float>(a_type, b_type); - case CellType::INT: return get_fun<T, int>(a_type, b_type); + case CellType::INT8: return get_fun<T, Int8Float>(a_type, b_type); + default: abort(); } - abort(); } //----------------------------------------------------------------------------- @@ -575,17 +549,17 @@ Sum3::Self::Self() //----------------------------------------------------------------------------- TEST("require that self-updating cached function pointer 'a op b -> c' works") { - std::vector<int> a({1,2,3}); - std::vector<float> b({1.5,2.5,3.5}); - std::vector<double> c(3, 0.0); - TypedCells a_cells(a); - TypedCells b_cells(b); - TypedCells c_cells(c); + std::vector<Int8Float> a({1,2,3}); + std::vector<float> b({1.5,2.5,3.5}); + std::vector<double> c(3, 0.0); + TypedCells a_cells(a); + TypedCells b_cells(b); + TypedCells c_cells(c); CellwiseAdd3 op; EXPECT_EQUAL(op.self.my_fun, (&cellwise_add<double,double,double>)); op.call(a_cells, b_cells, c_cells, 3); - EXPECT_EQUAL(op.self.my_fun, (&cellwise_add<int,float,double>)); + EXPECT_EQUAL(op.self.my_fun, (&cellwise_add<Int8Float,float,double>)); EXPECT_NOT_EQUAL(op.self.my_fun, (&cellwise_add<double,double,double>)); EXPECT_EQUAL(c[0], 2.5); @@ -594,29 +568,40 @@ TEST("require that self-updating cached function pointer 'a op b -> c' works") { } TEST("require that self-updating cached function pointer 'dot product' with return value works") { - std::vector<int> a({1,2,3}); - std::vector<float> b({1.5,2.5,3.5}); - TypedCells a_cells(a); - TypedCells b_cells(b); - double expect = 1.5 + (2 * 2.5) + (3 * 3.5); + std::vector<Int8Float> a({1,2,3}); + std::vector<float> b({1.5,2.5,3.5}); + TypedCells a_cells(a); + TypedCells b_cells(b); + double expect = 1.5 + (2 * 2.5) + (3 * 3.5); DotProduct3 op; EXPECT_EQUAL(op.self.my_fun, (&dot_product<double,double>)); EXPECT_EQUAL(expect, op.call(a_cells, b_cells, 3)); - EXPECT_EQUAL(op.self.my_fun, (&dot_product<int,float>)); + EXPECT_EQUAL(op.self.my_fun, (&dot_product<Int8Float,float>)); EXPECT_NOT_EQUAL(op.self.my_fun, (&dot_product<double,double>)); } TEST("require that self-updating cached function pointer 'sum' with return value works") { - std::vector<int> a({1,2,3}); - TypedCells a_cells(a); - double expect = (1 + 2 + 3); + std::vector<Int8Float> a({1,2,3}); + TypedCells a_cells(a); + double expect = (1 + 2 + 3); Sum3 op; EXPECT_EQUAL(op.self.my_fun, (&sum<double>)); EXPECT_EQUAL(expect, op.call(a_cells)); - EXPECT_EQUAL(op.self.my_fun, (&sum<int>)); + EXPECT_EQUAL(op.self.my_fun, (&sum<Int8Float>)); EXPECT_NOT_EQUAL(op.self.my_fun, (&sum<double>)); } +TEST("require that non_existing_attribute_value can be controlled") { + float values[3] = {0,1,2}; + EXPECT_FALSE(TypedCells().non_existing_attribute_value()); + EXPECT_FALSE(TypedCells(values, CellType::FLOAT, 3).non_existing_attribute_value()); + EXPECT_FALSE(TypedCells(ConstArrayRef<double>()).non_existing_attribute_value()); + EXPECT_FALSE(TypedCells(ConstArrayRef<float>()).non_existing_attribute_value()); + EXPECT_FALSE(TypedCells(ConstArrayRef<Int8Float>()).non_existing_attribute_value()); + EXPECT_FALSE(TypedCells(ConstArrayRef<BFloat16>()).non_existing_attribute_value()); + EXPECT_TRUE(TypedCells::create_non_existing_attribute_value(values, CellType::FLOAT, 3).non_existing_attribute_value()); +} + TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/eval/src/vespa/eval/eval/typed_cells.h b/eval/src/vespa/eval/eval/typed_cells.h index 3dd8c30a3a9..7aa7debff30 100644 --- a/eval/src/vespa/eval/eval/typed_cells.h +++ b/eval/src/vespa/eval/eval/typed_cells.h @@ -11,7 +11,8 @@ namespace vespalib::eval { struct TypedCells { const void *data; - size_t size:56; + size_t size:55; + bool _non_existing_attribute_value:1; CellType type; explicit TypedCells(ConstArrayRef<double> cells) noexcept : data(cells.begin()), size(cells.size()), type(CellType::DOUBLE) {} @@ -22,6 +23,12 @@ struct TypedCells { TypedCells() noexcept : data(nullptr), size(0), type(CellType::DOUBLE) {} TypedCells(const void *dp, CellType ct, size_t sz) noexcept : data(dp), size(sz), type(ct) {} + static TypedCells create_non_existing_attribute_value(const void *dp, CellType ct, size_t sz) { + TypedCells cells(dp, ct, sz); + cells._non_existing_attribute_value = true; + return cells; + } + template <typename T> bool check_type() const noexcept { return check_cell_type<T>(type); } template <typename T> ConstArrayRef<T> typify() const noexcept { @@ -36,7 +43,13 @@ struct TypedCells { TypedCells(const TypedCells &other) noexcept = default; TypedCells & operator= (TypedCells &&other) noexcept = default; TypedCells & operator= (const TypedCells &other) noexcept = default; - bool valid() const noexcept { return size != 0; } + /** + * This signals that this actually points to a value that is the default value + * when no value has set for the attribute. + * TODO: This does not belong here, but as it is used as an interface multiple places it must be so + * until we come up with a better solution. + */ + bool non_existing_attribute_value() const noexcept { return _non_existing_attribute_value; } }; } // namespace diff --git a/searchlib/src/tests/attribute/extendattributes/extendattribute_test.cpp b/searchlib/src/tests/attribute/extendattributes/extendattribute_test.cpp index d67757a3811..0c60b376361 100644 --- a/searchlib/src/tests/attribute/extendattributes/extendattribute_test.cpp +++ b/searchlib/src/tests/attribute/extendattributes/extendattribute_test.cpp @@ -224,7 +224,7 @@ void ExtendAttributeTest::testExtendRaw(AttributeVector& attr) void ExtendAttributeTest::testExtendTensor(AttributeVector& attr) { - std::vector<double> empty_cells{}; + std::vector<double> empty_cells{0, 0}; std::vector<double> spec0_dense_cells{1.0, 2.0}; std::vector<double> spec0_mixed_cells0{3.0, 4.0}; std::vector<double> spec0_mixed_cells1{5.0, 6.0}; diff --git a/searchlib/src/tests/tensor/hnsw_index/hnsw_index_test.cpp b/searchlib/src/tests/tensor/hnsw_index/hnsw_index_test.cpp index 31b147c0b5c..d50677314df 100644 --- a/searchlib/src/tests/tensor/hnsw_index/hnsw_index_test.cpp +++ b/searchlib/src/tests/tensor/hnsw_index/hnsw_index_test.cpp @@ -12,6 +12,7 @@ #include <vespa/searchlib/tensor/random_level_generator.h> #include <vespa/searchlib/tensor/inv_log_level_generator.h> #include <vespa/searchlib/tensor/subspace_type.h> +#include <vespa/searchlib/tensor/empty_subspace.h> #include <vespa/searchlib/tensor/vector_bundle.h> #include <vespa/searchlib/queryeval/global_filter.h> #include <vespa/vespalib/datastore/compaction_spec.h> @@ -49,6 +50,7 @@ private: using ArrayRef = vespalib::ConstArrayRef<FloatType>; mutable std::vector<Vector> _vectors; SubspaceType _subspace_type; + EmptySubspace _empty; mutable uint32_t _get_vector_count; mutable uint32_t _schedule_clear_tensor; mutable uint32_t _cleared_tensor_docid; @@ -57,6 +59,7 @@ public: MyDocVectorAccess() : _vectors(), _subspace_type(ValueType::make_type(get_cell_type<FloatType>(), {{"dims", 2}})), + _empty(_subspace_type), _get_vector_count(0), _schedule_clear_tensor(0), _cleared_tensor_docid(0) @@ -87,7 +90,7 @@ public: if (subspace < bundle.subspaces()) { return bundle.cells(subspace); } - return { nullptr, _subspace_type.cell_type(), 0 }; + return _empty.cells(); } VectorBundle get_vectors(uint32_t docid) const noexcept override { ArrayRef ref(_vectors[docid]); @@ -128,12 +131,12 @@ public: double min_rawscore() const noexcept override { return _real->min_rawscore(); } double calc(TypedCells rhs) const noexcept override { - EXPECT_TRUE(rhs.valid()); + EXPECT_FALSE(rhs.non_existing_attribute_value()); return _real->calc(rhs); } double calc_with_limit(TypedCells rhs, double limit) const noexcept override { - EXPECT_TRUE(rhs.valid()); + EXPECT_FALSE(rhs.non_existing_attribute_value()); return _real->calc_with_limit(rhs, limit); } }; @@ -152,12 +155,12 @@ public: ~MyDistanceFunctionFactory() override; std::unique_ptr<BoundDistanceFunction> for_query_vector(TypedCells lhs) override { - EXPECT_TRUE(lhs.valid()); + EXPECT_FALSE(lhs.non_existing_attribute_value()); return std::make_unique<MyBoundDistanceFunction>(_real->for_query_vector(lhs)); } std::unique_ptr<BoundDistanceFunction> for_insertion_vector(TypedCells lhs) override { - EXPECT_TRUE(lhs.valid()); + EXPECT_FALSE(lhs.non_existing_attribute_value()); return std::make_unique<MyBoundDistanceFunction>(_real->for_insertion_vector(lhs)); } }; diff --git a/searchlib/src/vespa/searchlib/tensor/distance_calculator.h b/searchlib/src/vespa/searchlib/tensor/distance_calculator.h index 7ff9448c5af..1bdd3b39711 100644 --- a/searchlib/src/vespa/searchlib/tensor/distance_calculator.h +++ b/searchlib/src/vespa/searchlib/tensor/distance_calculator.h @@ -45,7 +45,7 @@ public: if (has_single_subspace) { auto cells = _attr_tensor.get_vector(docid, 0); double min_rawscore = _dist_fun->min_rawscore(); - if ( ! cells.valid() ) [[unlikely]] { + if ( cells.non_existing_attribute_value() ) [[unlikely]] { return min_rawscore; } return std::max(min_rawscore, _dist_fun->to_rawscore(_dist_fun->calc(cells))); @@ -66,7 +66,7 @@ public: double calc_with_limit(uint32_t docid, double limit) const noexcept { if (has_single_subspace) { auto cells = _attr_tensor.get_vector(docid, 0); - if ( ! cells.valid() ) [[unlikely]] { + if ( cells.non_existing_attribute_value() ) [[unlikely]] { return std::numeric_limits<double>::max(); } return _dist_fun->calc_with_limit(cells, limit); diff --git a/searchlib/src/vespa/searchlib/tensor/empty_subspace.cpp b/searchlib/src/vespa/searchlib/tensor/empty_subspace.cpp index a7168b5eae6..131dcf05c60 100644 --- a/searchlib/src/vespa/searchlib/tensor/empty_subspace.cpp +++ b/searchlib/src/vespa/searchlib/tensor/empty_subspace.cpp @@ -3,6 +3,8 @@ #include "empty_subspace.h" #include "subspace_type.h" +using vespalib::eval::TypedCells; + namespace search::tensor { EmptySubspace::EmptySubspace(const SubspaceType& type) @@ -11,7 +13,7 @@ EmptySubspace::EmptySubspace(const SubspaceType& type) { _empty_space.resize(type.mem_size()); // Set size to zero to signal empty/invalid subspace - _cells = vespalib::eval::TypedCells(_empty_space.data(), type.cell_type(), 0); + _cells = TypedCells::create_non_existing_attribute_value(_empty_space.data(), type.cell_type(), type.size()); } EmptySubspace::~EmptySubspace() = default; diff --git a/searchlib/src/vespa/searchlib/tensor/hnsw_index.cpp b/searchlib/src/vespa/searchlib/tensor/hnsw_index.cpp index cdc3e81782a..1db688156e0 100644 --- a/searchlib/src/vespa/searchlib/tensor/hnsw_index.cpp +++ b/searchlib/src/vespa/searchlib/tensor/hnsw_index.cpp @@ -183,7 +183,7 @@ bool HnswIndex<type>::have_closer_distance(HnswTraversalCandidate candidate, const HnswTraversalCandidateVector& result) const { auto candidate_vector = get_vector(candidate.nodeid); - if (!candidate_vector.valid()) { + if (candidate_vector.non_existing_attribute_value()) { /* * We are in a read thread and the write thread has removed the * tensor for the candidate. Return true to prevent the candidate @@ -319,7 +319,7 @@ namespace { double calc_distance_helper(const BoundDistanceFunction &df, vespalib::eval::TypedCells rhs) { - if (!rhs.valid()) [[unlikely]] { + if (rhs.non_existing_attribute_value()) [[unlikely]] { /* * We are in a read thread and the write thread has removed the * tensor. |