summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeir Storli <geirst@yahooinc.com>2022-04-20 16:11:46 +0200
committerGitHub <noreply@github.com>2022-04-20 16:11:46 +0200
commit8b948d5a85225af85e1b694e9259bceb75b35800 (patch)
tree711e89fc6394cda97ec11dd7c6bc009a11584885
parent0cbd9956e29ac0706e1e1b569609536c3fbc8dd6 (diff)
parentdb6e199a7cff0d8d57512231016e0d041a4ea92b (diff)
Merge pull request #22176 from vespa-engine/toregge/support-multi-value-read-view-for-imported-attribute-vectors
Enable MultiValueReadView for imported attribute vectors.
-rw-r--r--searchlib/src/tests/attribute/multi_value_read_view/multi_value_read_view_test.cpp163
-rw-r--r--searchlib/src/vespa/searchlib/attribute/CMakeLists.txt1
-rw-r--r--searchlib/src/vespa/searchlib/attribute/imported_attribute_vector_read_guard.cpp115
-rw-r--r--searchlib/src/vespa/searchlib/attribute/imported_attribute_vector_read_guard.h22
-rw-r--r--searchlib/src/vespa/searchlib/attribute/imported_multi_value_read_view.cpp47
-rw-r--r--searchlib/src/vespa/searchlib/attribute/imported_multi_value_read_view.h33
6 files changed, 359 insertions, 22 deletions
diff --git a/searchlib/src/tests/attribute/multi_value_read_view/multi_value_read_view_test.cpp b/searchlib/src/tests/attribute/multi_value_read_view/multi_value_read_view_test.cpp
index 43d819ca966..c81fea79590 100644
--- a/searchlib/src/tests/attribute/multi_value_read_view/multi_value_read_view_test.cpp
+++ b/searchlib/src/tests/attribute/multi_value_read_view/multi_value_read_view_test.cpp
@@ -1,19 +1,86 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/document/base/documentid.h>
#include <vespa/searchcommon/attribute/i_multi_value_attribute.h>
#include <vespa/searchcommon/attribute/multi_value_traits.h>
#include <vespa/searchlib/attribute/attributefactory.h>
+#include <vespa/searchlib/attribute/attribute_read_guard.h>
#include <vespa/searchlib/attribute/extendableattributes.h>
#include <vespa/searchlib/attribute/floatbase.h>
+#include <vespa/searchlib/attribute/imported_attribute_vector.h>
+#include <vespa/searchlib/attribute/imported_attribute_vector_factory.h>
#include <vespa/searchlib/attribute/integerbase.h>
+#include <vespa/searchlib/attribute/reference_attribute.h>
#include <vespa/searchlib/attribute/stringbase.h>
+#include <vespa/searchlib/common/i_document_meta_store_context.h>
+#include <vespa/searchlib/test/mock_gid_to_lid_mapping.h>
#include <vespa/vespalib/gtest/gtest.h>
#include <vespa/vespalib/util/stash.h>
-
+using document::GlobalId;
+using document::DocumentId;
namespace search::attribute {
+using test::MockGidToLidMapperFactory;
+
+namespace {
+
+GlobalId toGid(vespalib::stringref docId) {
+ return DocumentId(docId).getGlobalId();
+}
+
+vespalib::string doc1("id:test:music::1");
+vespalib::string doc2("id:test:music::2");
+
+struct MyGidToLidMapperFactory : public MockGidToLidMapperFactory
+{
+ MyGidToLidMapperFactory()
+ : MockGidToLidMapperFactory()
+ {
+ _map.insert({toGid(doc1), 1});
+ _map.insert({toGid(doc2), 2});
+ }
+};
+
+struct MockReadGuard : public IDocumentMetaStoreContext::IReadGuard {
+ virtual const search::IDocumentMetaStore &get() const override {
+ search::IDocumentMetaStore *nullStore = nullptr;
+ return static_cast<search::IDocumentMetaStore &>(*nullStore);
+ }
+};
+
+struct MockDocumentMetaStoreContext : public IDocumentMetaStoreContext
+{
+ std::unique_ptr<IReadGuard> getReadGuard() const override;
+};
+
+std::unique_ptr<IDocumentMetaStoreContext::IReadGuard>
+MockDocumentMetaStoreContext::getReadGuard() const
+{
+ return std::make_unique<MockReadGuard>();
+}
+
+
+std::shared_ptr<ReferenceAttribute>
+create_reference_attribute(const vespalib::string &name, const std::shared_ptr<IGidToLidMapperFactory> gid_to_lid_mapper_factory)
+{
+ auto attr = std::make_shared<ReferenceAttribute>(name, Config(BasicType::REFERENCE));
+ attr->addReservedDoc();
+ while (attr->getNumDocs() < 20u) {
+ uint32_t doc_id = 0;
+ attr->addDoc(doc_id);
+ EXPECT_NE(0u, doc_id);
+ }
+ attr->update(4, toGid(doc1));
+ attr->update(11, toGid(doc2));
+ attr->setGidToLidMapperFactory(gid_to_lid_mapper_factory);
+ attr->populateTargetLids({});
+ return attr;
+}
+
+}
+
class TestParam {
BasicType _basic_type;
@@ -35,8 +102,12 @@ std::ostream& operator<<(std::ostream& os, const TestParam& param)
class MultiValueReadViewTest : public ::testing::TestWithParam<TestParam>
{
protected:
+ std::shared_ptr<IGidToLidMapperFactory> _gid_to_lid_mapper_factory;
+ std::shared_ptr<ReferenceAttribute> _reference_attribute;
MultiValueReadViewTest()
- : ::testing::TestWithParam<TestParam>()
+ : ::testing::TestWithParam<TestParam>(),
+ _gid_to_lid_mapper_factory(std::make_shared<MyGidToLidMapperFactory>()),
+ _reference_attribute(create_reference_attribute("ref", _gid_to_lid_mapper_factory))
{
}
~MultiValueReadViewTest() override = default;
@@ -45,15 +116,18 @@ protected:
void populate_helper(AttributeVector& attr, const std::vector<BaseType>& values);
void populate(AttributeVector& attr);
template <typename MultiValueType>
- void check_values_helper(const AttributeVector &attr, const std::vector<multivalue::ValueType_t<MultiValueType>>& exp_values);
+ void check_values_helper(const IAttributeVector &attr, const std::vector<multivalue::ValueType_t<MultiValueType>>& exp_values);
template <typename BasicType>
- void check_integer_values(const AttributeVector &attr);
+ void check_integer_values(const IAttributeVector &attr);
template <typename BasicType>
- void check_floating_point_values(const AttributeVector &attr);
- void check_string_values(const AttributeVector &attr);
- void check_values(const AttributeVector& attr);
+ void check_floating_point_values(const IAttributeVector &attr);
+ void check_string_values(const IAttributeVector &attr);
+ void check_values(const IAttributeVector& attr);
+ std::shared_ptr<AttributeVector> make_attribute(CollectionType collection_type, bool fast_search);
+ std::shared_ptr<ReadableAttributeVector> make_imported_attribute(std::shared_ptr<AttributeVector> target);
std::shared_ptr<AttributeVector> make_extendable_attribute(CollectionType collection_type);
void test_normal_attribute_vector(CollectionType collection_type, bool fast_search);
+ void test_imported_attribute_vector(CollectionType collection_type, bool fast_search);
void test_extendable_attribute_vector(CollectionType collection_type);
};
@@ -135,20 +209,21 @@ struct CompareValues<const char *>
template <typename MultiValueType>
void
-MultiValueReadViewTest::check_values_helper(const AttributeVector &attr, const std::vector<multivalue::ValueType_t<MultiValueType>>& exp_values)
+MultiValueReadViewTest::check_values_helper(const IAttributeVector &attr, const std::vector<multivalue::ValueType_t<MultiValueType>>& exp_values)
{
vespalib::Stash stash;
auto mv_attr = attr.as_multi_value_attribute();
EXPECT_NE(nullptr, mv_attr);
auto read_view = mv_attr->make_read_view(IMultiValueAttribute::Tag<MultiValueType>(), stash);
EXPECT_NE(nullptr, read_view);
- auto values = read_view->get_values(1);
+ bool is_imported = attr.isImported();
+ auto values = read_view->get_values(is_imported ? 4 : 1);
EXPECT_TRUE(values.empty());
- values = read_view->get_values(2);
+ values = read_view->get_values(is_imported ? 11 : 2);
std::vector<MultiValueType> values_copy(values.begin(), values.end());
bool was_array = true;
CompareValues<multivalue::ValueType_t<MultiValueType>> compare_values;
- if (attr.getConfig().collectionType().type() == CollectionType::Type::WSET) {
+ if (attr.getCollectionType() == CollectionType::Type::WSET) {
std::sort(values_copy.begin(), values_copy.end(), compare_values);
was_array = false;
}
@@ -166,7 +241,7 @@ MultiValueReadViewTest::check_values_helper(const AttributeVector &attr, const s
template <typename BasicType>
void
-MultiValueReadViewTest::check_integer_values(const AttributeVector &attr)
+MultiValueReadViewTest::check_integer_values(const IAttributeVector &attr)
{
std::vector<BasicType> exp_values{42, 44};
check_values_helper<BasicType>(attr, exp_values);
@@ -175,7 +250,7 @@ MultiValueReadViewTest::check_integer_values(const AttributeVector &attr)
template <typename BasicType>
void
-MultiValueReadViewTest::check_floating_point_values(const AttributeVector &attr)
+MultiValueReadViewTest::check_floating_point_values(const IAttributeVector &attr)
{
std::vector<BasicType> exp_values{42.0, 44.0};
check_values_helper<BasicType>(attr, exp_values);
@@ -183,7 +258,7 @@ MultiValueReadViewTest::check_floating_point_values(const AttributeVector &attr)
}
void
-MultiValueReadViewTest::check_string_values(const AttributeVector &attr)
+MultiValueReadViewTest::check_string_values(const IAttributeVector &attr)
{
std::vector<const char *> exp_values{"42", "44"};
check_values_helper<const char *>(attr, exp_values);
@@ -191,9 +266,9 @@ MultiValueReadViewTest::check_string_values(const AttributeVector &attr)
}
void
-MultiValueReadViewTest::check_values(const AttributeVector& attr)
+MultiValueReadViewTest::check_values(const IAttributeVector& attr)
{
- switch (attr.getConfig().basicType().type()) {
+ switch (attr.getBasicType()) {
case BasicType::Type::INT8:
check_integer_values<int8_t>(attr);
break;
@@ -221,6 +296,27 @@ MultiValueReadViewTest::check_values(const AttributeVector& attr)
}
std::shared_ptr<AttributeVector>
+MultiValueReadViewTest::make_attribute(CollectionType collection_type, bool fast_search)
+{
+ auto param = GetParam();
+ Config config(param.basic_type(), collection_type);
+ config.setFastSearch(fast_search);
+ auto attr = AttributeFactory::createAttribute("attr", config);
+ return attr;
+}
+
+std::shared_ptr<ReadableAttributeVector>
+MultiValueReadViewTest::make_imported_attribute(std::shared_ptr<AttributeVector> target)
+{
+ return ImportedAttributeVectorFactory::create("imported",
+ _reference_attribute,
+ std::make_shared<MockDocumentMetaStoreContext>(),
+ target,
+ std::make_shared<MockDocumentMetaStoreContext>(),
+ false);
+}
+
+std::shared_ptr<AttributeVector>
MultiValueReadViewTest::make_extendable_attribute(CollectionType collection_type)
{
vespalib::string name("attr");
@@ -267,15 +363,22 @@ MultiValueReadViewTest::make_extendable_attribute(CollectionType collection_type
void
MultiValueReadViewTest::test_normal_attribute_vector(CollectionType collection_type, bool fast_search)
{
- auto param = GetParam();
- Config config(param.basic_type(), collection_type);
- config.setFastSearch(fast_search);
- auto attr = AttributeFactory::createAttribute("attr", config);
+ auto attr = make_attribute(collection_type, fast_search);
populate(*attr);
check_values(*attr);
}
void
+MultiValueReadViewTest::test_imported_attribute_vector(CollectionType collection_type, bool fast_search)
+{
+ auto attr = make_attribute(collection_type, fast_search);
+ populate(*attr);
+ auto imported_attr = make_imported_attribute(attr);
+ auto guard = imported_attr->makeReadGuard(false);
+ check_values(**guard);
+}
+
+void
MultiValueReadViewTest::test_extendable_attribute_vector(CollectionType collection_type)
{
auto attr = make_extendable_attribute(collection_type);
@@ -306,6 +409,26 @@ TEST_P(MultiValueReadViewTest, test_enumerated_weighted_set)
test_normal_attribute_vector(CollectionType::Type::WSET, true);
};
+TEST_P(MultiValueReadViewTest, test_imported_array)
+{
+ test_imported_attribute_vector(CollectionType::Type::ARRAY, false);
+};
+
+TEST_P(MultiValueReadViewTest, test_imported_enumerated_array)
+{
+ test_imported_attribute_vector(CollectionType::Type::ARRAY, true);
+};
+
+TEST_P(MultiValueReadViewTest, test_importe_weighted_set)
+{
+ test_imported_attribute_vector(CollectionType::Type::WSET, false);
+};
+
+TEST_P(MultiValueReadViewTest, test_imported_enumerated_weighted_set)
+{
+ test_imported_attribute_vector(CollectionType::Type::WSET, true);
+};
+
TEST_P(MultiValueReadViewTest, test_extendable_array)
{
test_extendable_attribute_vector(CollectionType::Type::ARRAY);
diff --git a/searchlib/src/vespa/searchlib/attribute/CMakeLists.txt b/searchlib/src/vespa/searchlib/attribute/CMakeLists.txt
index 108beb96833..5fa691394fb 100644
--- a/searchlib/src/vespa/searchlib/attribute/CMakeLists.txt
+++ b/searchlib/src/vespa/searchlib/attribute/CMakeLists.txt
@@ -62,6 +62,7 @@ vespa_add_library(searchlib_attribute OBJECT
imported_attribute_vector.cpp
imported_attribute_vector_factory.cpp
imported_attribute_vector_read_guard.cpp
+ imported_multi_value_read_view.cpp
imported_search_context.cpp
integerbase.cpp
ipostinglistsearchcontext.cpp
diff --git a/searchlib/src/vespa/searchlib/attribute/imported_attribute_vector_read_guard.cpp b/searchlib/src/vespa/searchlib/attribute/imported_attribute_vector_read_guard.cpp
index f1ae5252031..c8a6309c282 100644
--- a/searchlib/src/vespa/searchlib/attribute/imported_attribute_vector_read_guard.cpp
+++ b/searchlib/src/vespa/searchlib/attribute/imported_attribute_vector_read_guard.cpp
@@ -2,9 +2,11 @@
#include "imported_attribute_vector_read_guard.h"
#include "imported_attribute_vector.h"
+#include "imported_multi_value_read_view.h"
#include "imported_search_context.h"
#include "reference_attribute.h"
#include <vespa/searchlib/query/query_term_simple.h>
+#include <vespa/vespalib/util/stash.h>
namespace search::attribute {
@@ -120,7 +122,7 @@ const tensor::ITensorAttribute *ImportedAttributeVectorReadGuard::asTensorAttrib
}
const attribute::IMultiValueAttribute* ImportedAttributeVectorReadGuard::as_multi_value_attribute() const {
- return nullptr;
+ return this;
}
BasicType::Type ImportedAttributeVectorReadGuard::getBasicType() const {
@@ -156,6 +158,117 @@ bool ImportedAttributeVectorReadGuard::isImported() const
return true;
}
+template <typename MultiValueType>
+const IMultiValueReadView<MultiValueType>*
+ImportedAttributeVectorReadGuard::make_read_view_helper(Tag<MultiValueType> tag, vespalib::Stash &stash) const
+{
+ auto target_mv_attr = _target_attribute.as_multi_value_attribute();
+ if (target_mv_attr == nullptr) {
+ return nullptr;
+ }
+ auto target_read_view = target_mv_attr->make_read_view(tag, stash);
+ if (target_read_view == nullptr) {
+ return nullptr;
+ }
+ return &stash.create<ImportedMultiValueReadView<MultiValueType>>(_targetLids, target_read_view);
+}
+
+const IArrayReadView<int8_t>*
+ImportedAttributeVectorReadGuard::make_read_view(ArrayTag<int8_t> tag, vespalib::Stash& stash) const
+{
+ return make_read_view_helper(tag, stash);
+}
+
+const IArrayReadView<int16_t>*
+ImportedAttributeVectorReadGuard::make_read_view(ArrayTag<int16_t> tag, vespalib::Stash& stash) const
+{
+ return make_read_view_helper(tag, stash);
+}
+
+const IArrayReadView<int32_t>*
+ImportedAttributeVectorReadGuard::make_read_view(ArrayTag<int32_t> tag, vespalib::Stash& stash) const
+{
+ return make_read_view_helper(tag, stash);
+}
+
+const IArrayReadView<int64_t>*
+ImportedAttributeVectorReadGuard::make_read_view(ArrayTag<int64_t> tag, vespalib::Stash& stash) const
+{
+ return make_read_view_helper(tag, stash);
+}
+
+const IArrayReadView<float>*
+ImportedAttributeVectorReadGuard::make_read_view(ArrayTag<float> tag, vespalib::Stash& stash) const
+{
+ return make_read_view_helper(tag, stash);
+}
+
+const IArrayReadView<double>*
+ImportedAttributeVectorReadGuard::make_read_view(ArrayTag<double> tag, vespalib::Stash& stash) const
+{
+ return make_read_view_helper(tag, stash);
+}
+
+const IArrayReadView<const char*>*
+ImportedAttributeVectorReadGuard::make_read_view(ArrayTag<const char*> tag, vespalib::Stash& stash) const
+{
+ return make_read_view_helper(tag, stash);
+}
+
+const IWeightedSetReadView<int8_t>*
+ImportedAttributeVectorReadGuard::make_read_view(WeightedSetTag<int8_t> tag, vespalib::Stash& stash) const
+{
+ return make_read_view_helper(tag, stash);
+}
+
+const IWeightedSetReadView<int16_t>*
+ImportedAttributeVectorReadGuard::make_read_view(WeightedSetTag<int16_t> tag, vespalib::Stash& stash) const
+{
+ return make_read_view_helper(tag, stash);
+}
+
+const IWeightedSetReadView<int32_t>*
+ImportedAttributeVectorReadGuard::make_read_view(WeightedSetTag<int32_t> tag, vespalib::Stash& stash) const
+{
+ return make_read_view_helper(tag, stash);
+}
+
+const IWeightedSetReadView<int64_t>*
+ImportedAttributeVectorReadGuard::make_read_view(WeightedSetTag<int64_t> tag, vespalib::Stash& stash) const
+{
+ return make_read_view_helper(tag, stash);
+}
+
+const IWeightedSetReadView<float>*
+ImportedAttributeVectorReadGuard::make_read_view(WeightedSetTag<float> tag, vespalib::Stash& stash) const
+{
+ return make_read_view_helper(tag, stash);
+}
+
+const IWeightedSetReadView<double>*
+ImportedAttributeVectorReadGuard:: make_read_view(WeightedSetTag<double> tag, vespalib::Stash& stash) const
+{
+ return make_read_view_helper(tag, stash);
+}
+
+const IWeightedSetReadView<const char*>*
+ImportedAttributeVectorReadGuard::make_read_view(WeightedSetTag<const char*> tag, vespalib::Stash& stash) const
+{
+ return make_read_view_helper(tag, stash);
+}
+
+const IArrayEnumReadView*
+ImportedAttributeVectorReadGuard::make_read_view(ArrayEnumTag tag, vespalib::Stash& stash) const
+{
+ return make_read_view_helper(tag, stash);
+}
+
+const IWeightedSetEnumReadView*
+ImportedAttributeVectorReadGuard::make_read_view(WeightedSetEnumTag tag, vespalib::Stash& stash) const
+{
+ return make_read_view_helper(tag, stash);
+}
+
bool ImportedAttributeVectorReadGuard::isUndefined(DocId doc) const {
return _target_attribute.isUndefined(getTargetLid(doc));
}
diff --git a/searchlib/src/vespa/searchlib/attribute/imported_attribute_vector_read_guard.h b/searchlib/src/vespa/searchlib/attribute/imported_attribute_vector_read_guard.h
index f5b896e2da5..9e596078678 100644
--- a/searchlib/src/vespa/searchlib/attribute/imported_attribute_vector_read_guard.h
+++ b/searchlib/src/vespa/searchlib/attribute/imported_attribute_vector_read_guard.h
@@ -5,6 +5,7 @@
#include "attribute_read_guard.h"
#include "attributeguard.h"
#include <vespa/searchcommon/attribute/iattributevector.h>
+#include <vespa/searchcommon/attribute/i_multi_value_attribute.h>
#include <vespa/searchlib/common/i_document_meta_store_context.h>
#include <vespa/vespalib/datastore/atomic_value_wrapper.h>
#include <vespa/vespalib/util/arrayref.h>
@@ -27,7 +28,8 @@ class ReferenceAttribute;
* boundary check is setup during construction.
*/
class ImportedAttributeVectorReadGuard : public IAttributeVector,
- public AttributeReadGuard
+ public AttributeReadGuard,
+ public IMultiValueAttribute
{
private:
using AtomicTargetLid = vespalib::datastore::AtomicValueWrapper<uint32_t>;
@@ -86,6 +88,24 @@ public:
uint32_t getCommittedDocIdLimit() const override;
bool isImported() const override;
bool isUndefined(DocId doc) const override;
+ template <typename MultiValueType>
+ const IMultiValueReadView<MultiValueType>* make_read_view_helper(Tag<MultiValueType> tag, vespalib::Stash& stash) const;
+ const IArrayReadView<int8_t>* make_read_view(ArrayTag<int8_t> tag, vespalib::Stash& stash) const override;
+ const IArrayReadView<int16_t>* make_read_view(ArrayTag<int16_t> tag, vespalib::Stash& stash) const override;
+ const IArrayReadView<int32_t>* make_read_view(ArrayTag<int32_t> tag, vespalib::Stash& stash) const override;
+ const IArrayReadView<int64_t>* make_read_view(ArrayTag<int64_t> tag, vespalib::Stash& stash) const override;
+ const IArrayReadView<float>* make_read_view(ArrayTag<float> tag, vespalib::Stash& stash) const override;
+ const IArrayReadView<double>* make_read_view(ArrayTag<double> tag, vespalib::Stash& stash) const override;
+ const IArrayReadView<const char*>* make_read_view(ArrayTag<const char*> tag, vespalib::Stash& stash) const override;
+ const IWeightedSetReadView<int8_t>* make_read_view(WeightedSetTag<int8_t> tag, vespalib::Stash& stash) const override;
+ const IWeightedSetReadView<int16_t>* make_read_view(WeightedSetTag<int16_t> tag, vespalib::Stash& stash) const override;
+ const IWeightedSetReadView<int32_t>* make_read_view(WeightedSetTag<int32_t> tag, vespalib::Stash& stash) const override;
+ const IWeightedSetReadView<int64_t>* make_read_view(WeightedSetTag<int64_t> tag, vespalib::Stash& stash) const override;
+ const IWeightedSetReadView<float>* make_read_view(WeightedSetTag<float> tag, vespalib::Stash& stash) const override;
+ const IWeightedSetReadView<double>* make_read_view(WeightedSetTag<double> tag, vespalib::Stash& stash) const override;
+ const IWeightedSetReadView<const char*>* make_read_view(WeightedSetTag<const char*> tag, vespalib::Stash& stash) const override;
+ const IArrayEnumReadView* make_read_view(ArrayEnumTag tag, vespalib::Stash& stash) const override;
+ const IWeightedSetEnumReadView* make_read_view(WeightedSetEnumTag tag, vespalib::Stash& stash) const override;
protected:
long onSerializeForAscendingSort(DocId doc, void * serTo, long available,
diff --git a/searchlib/src/vespa/searchlib/attribute/imported_multi_value_read_view.cpp b/searchlib/src/vespa/searchlib/attribute/imported_multi_value_read_view.cpp
new file mode 100644
index 00000000000..b36d321694e
--- /dev/null
+++ b/searchlib/src/vespa/searchlib/attribute/imported_multi_value_read_view.cpp
@@ -0,0 +1,47 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "imported_multi_value_read_view.h"
+
+using vespalib::datastore::AtomicEntryRef;
+
+namespace search::attribute {
+
+template <typename MultiValueType>
+ImportedMultiValueReadView<MultiValueType>::ImportedMultiValueReadView(TargetLids target_lids, const IMultiValueReadView<MultiValueType>* target_read_view)
+ : _target_lids(target_lids),
+ _target_read_view(target_read_view)
+{
+}
+
+template <typename MultiValueType>
+ImportedMultiValueReadView<MultiValueType>::~ImportedMultiValueReadView() = default;
+
+template <typename MultiValueType>
+vespalib::ConstArrayRef<MultiValueType>
+ImportedMultiValueReadView<MultiValueType>::get_values(uint32_t docid) const
+{
+ auto target_lid = get_target_lid(docid);
+ return _target_read_view->get_values(target_lid);
+}
+
+using multivalue::WeightedValue;
+
+template class ImportedMultiValueReadView<int8_t>;
+template class ImportedMultiValueReadView<int16_t>;
+template class ImportedMultiValueReadView<int32_t>;
+template class ImportedMultiValueReadView<int64_t>;
+template class ImportedMultiValueReadView<float>;
+template class ImportedMultiValueReadView<double>;
+template class ImportedMultiValueReadView<AtomicEntryRef>;
+template class ImportedMultiValueReadView<const char*>;
+
+template class ImportedMultiValueReadView<WeightedValue<int8_t>>;
+template class ImportedMultiValueReadView<WeightedValue<int16_t>>;
+template class ImportedMultiValueReadView<WeightedValue<int32_t>>;
+template class ImportedMultiValueReadView<WeightedValue<int64_t>>;
+template class ImportedMultiValueReadView<WeightedValue<float>>;
+template class ImportedMultiValueReadView<WeightedValue<double>>;
+template class ImportedMultiValueReadView<WeightedValue<AtomicEntryRef>>;
+template class ImportedMultiValueReadView<WeightedValue<const char*>>;
+
+}
diff --git a/searchlib/src/vespa/searchlib/attribute/imported_multi_value_read_view.h b/searchlib/src/vespa/searchlib/attribute/imported_multi_value_read_view.h
new file mode 100644
index 00000000000..9ec54feca9e
--- /dev/null
+++ b/searchlib/src/vespa/searchlib/attribute/imported_multi_value_read_view.h
@@ -0,0 +1,33 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/searchcommon/attribute/i_multi_value_read_view.h>
+#include <vespa/vespalib/datastore/atomic_value_wrapper.h>
+
+namespace search::attribute {
+
+/**
+ * Multi value read view adapter for imported atributes vectors.
+ * Performs lid mapping.
+ * @tparam MultiValueType The multi-value type of the data to access.
+ */
+template <typename MultiValueType>
+class ImportedMultiValueReadView : public IMultiValueReadView<MultiValueType>
+{
+ using AtomicTargetLid = vespalib::datastore::AtomicValueWrapper<uint32_t>;
+ using TargetLids = vespalib::ConstArrayRef<AtomicTargetLid>;
+ TargetLids _target_lids;
+ const IMultiValueReadView<MultiValueType>* _target_read_view;
+
+ uint32_t get_target_lid(uint32_t lid) const {
+ // Check range to avoid reading memory beyond end of mapping array
+ return lid < _target_lids.size() ? _target_lids[lid].load_acquire() : 0u;
+ }
+public:
+ ImportedMultiValueReadView(TargetLids target_lids, const IMultiValueReadView<MultiValueType>* target_read_view);
+ ~ImportedMultiValueReadView() override;
+ vespalib::ConstArrayRef<MultiValueType> get_values(uint32_t docid) const override;
+};
+
+}