diff options
author | Geir Storli <geirst@verizonmedia.com> | 2020-06-05 07:39:01 +0000 |
---|---|---|
committer | Geir Storli <geirst@verizonmedia.com> | 2020-06-05 13:58:10 +0000 |
commit | 6e3e3f2ce4322be9d9c7bbafc71236f3cb834e5a (patch) | |
tree | 3cdfcf6f718bf21bc43ba9ccfbb2810c539df67d /searchsummary | |
parent | 4c7a62d81082a1e63613b3e3864ba4b9c17be292 (diff) |
Support filtering of matched elements for multi-value attributes.
Diffstat (limited to 'searchsummary')
11 files changed, 386 insertions, 151 deletions
diff --git a/searchsummary/CMakeLists.txt b/searchsummary/CMakeLists.txt index 787925521ef..3792f2b6218 100644 --- a/searchsummary/CMakeLists.txt +++ b/searchsummary/CMakeLists.txt @@ -26,6 +26,7 @@ vespa_define_module( src/tests/docsumformat src/tests/docsummary src/tests/docsummary/attribute_combiner + src/tests/docsummary/attributedfw src/tests/docsummary/matched_elements_filter src/tests/docsummary/slime_summary src/tests/extractkeywords diff --git a/searchsummary/src/tests/docsummary/attribute_combiner/CMakeLists.txt b/searchsummary/src/tests/docsummary/attribute_combiner/CMakeLists.txt index cffdef25e5b..3ac95211aec 100644 --- a/searchsummary/src/tests/docsummary/attribute_combiner/CMakeLists.txt +++ b/searchsummary/src/tests/docsummary/attribute_combiner/CMakeLists.txt @@ -5,6 +5,7 @@ vespa_add_executable(searchsummary_attribute_combiner_test_app TEST attribute_combiner_test.cpp DEPENDS searchsummary + searchsummary_test GTest::GTest ) vespa_add_test(NAME searchsummary_attribute_combiner_test_app COMMAND searchsummary_attribute_combiner_test_app) diff --git a/searchsummary/src/tests/docsummary/attribute_combiner/attribute_combiner_test.cpp b/searchsummary/src/tests/docsummary/attribute_combiner/attribute_combiner_test.cpp index c64c5b2ed7d..eaeaa27f053 100644 --- a/searchsummary/src/tests/docsummary/attribute_combiner/attribute_combiner_test.cpp +++ b/searchsummary/src/tests/docsummary/attribute_combiner/attribute_combiner_test.cpp @@ -1,19 +1,16 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include <vespa/searchcommon/common/undefinedvalues.h> -#include <vespa/searchlib/attribute/attributefactory.h> -#include <vespa/searchlib/attribute/attributemanager.h> #include <vespa/searchlib/attribute/attributevector.h> -#include <vespa/searchlib/attribute/attributevector.hpp> -#include <vespa/searchlib/attribute/floatbase.h> -#include <vespa/searchlib/attribute/integerbase.h> -#include <vespa/searchlib/attribute/stringbase.h> #include <vespa/searchlib/common/matching_elements.h> #include <vespa/searchlib/common/matching_elements_fields.h> #include <vespa/searchlib/util/slime_output_raw_buf_adapter.h> +#include <vespa/searchsummary/docsummary/docsumfieldwriter.h> #include <vespa/searchsummary/docsummary/docsumstate.h> #include <vespa/searchsummary/docsummary/docsum_field_writer_state.h> #include <vespa/searchsummary/docsummary/attribute_combiner_dfw.h> +#include <vespa/searchsummary/test/mock_attribute_manager.h> +#include <vespa/searchsummary/test/mock_state_callback.h> #include <vespa/searchsummary/test/slime_value.h> #include <vespa/vespalib/data/slime/slime.h> #include <vespa/vespalib/gtest/gtest.h> @@ -21,150 +18,24 @@ #include <vespa/log/log.h> LOG_SETUP("attribute_combiner_test"); -using search::AttributeFactory; -using search::AttributeManager; -using search::AttributeVector; -using search::FloatingPointAttribute; -using search::IntegerAttribute; -using search::MatchingElements; -using search::StringAttribute; using search::attribute::BasicType; -using search::attribute::CollectionType; -using search::attribute::Config; -using search::attribute::IAttributeVector; using search::attribute::getUndefined; using search::docsummary::AttributeCombinerDFW; using search::docsummary::GetDocsumsState; using search::docsummary::GetDocsumsStateCallback; using search::docsummary::IDocsumEnvironment; using search::docsummary::IDocsumFieldWriter; +using search::docsummary::test::MockAttributeManager; +using search::docsummary::test::MockStateCallback; using search::docsummary::test::SlimeValue; namespace { -struct AttributeManagerFixture -{ - AttributeManager mgr; - - AttributeManagerFixture(); - - ~AttributeManagerFixture(); - - template <typename AttributeType, typename ValueType> - void - buildAttribute(const vespalib::string &name, - BasicType type, - std::vector<std::vector<ValueType>> values); - - void - buildStringAttribute(const vespalib::string &name, - std::vector<std::vector<vespalib::string>> values); - void - buildFloatAttribute(const vespalib::string &name, - std::vector<std::vector<double>> values); - - void - buildIntegerAttribute(const vespalib::string &name, - BasicType type, - std::vector<std::vector<IAttributeVector::largeint_t>> values); -}; - -AttributeManagerFixture::AttributeManagerFixture() - : mgr() -{ - buildStringAttribute("array.name", {{"n1.1", "n1.2"}, {"n2"}, {"n3.1", "n3.2"}, {"", "n4.2"}, {}}); - buildIntegerAttribute("array.val", BasicType::Type::INT8, {{ 10, 11}, {20, 21 }, {30}, { getUndefined<int8_t>(), 41}, {}}); - buildFloatAttribute("array.fval", {{ 110.0}, { 120.0, 121.0 }, { 130.0, 131.0}, { getUndefined<double>(), 141.0 }, {}}); - buildStringAttribute("smap.key", {{"k1.1", "k1.2"}, {"k2"}, {"k3.1", "k3.2"}, {"", "k4.2"}, {}}); - buildStringAttribute("smap.value.name", {{"n1.1", "n1.2"}, {"n2"}, {"n3.1", "n3.2"}, {"", "n4.2"}, {}}); - buildIntegerAttribute("smap.value.val", BasicType::Type::INT8, {{ 10, 11}, {20, 21 }, {30}, { getUndefined<int8_t>(), 41}, {}}); - buildFloatAttribute("smap.value.fval", {{ 110.0}, { 120.0, 121.0 }, { 130.0, 131.0}, { getUndefined<double>(), 141.0 }, {}}); - buildStringAttribute("map.key", {{"k1.1", "k1.2"}, {"k2"}, {"k3.1"}, {"", "k4.2"}, {}}); - buildStringAttribute("map.value", {{"n1.1", "n1.2"}, {}, {"n3.1", "n3.2"}, {"", "n4.2"}, {}}); -} - -AttributeManagerFixture::~AttributeManagerFixture() = default; - -template <typename AttributeType, typename ValueType> -void -AttributeManagerFixture::buildAttribute(const vespalib::string &name, - BasicType type, - std::vector<std::vector<ValueType>> values) -{ - Config cfg(type, CollectionType::Type::ARRAY); - auto attrBase = AttributeFactory::createAttribute(name, cfg); - EXPECT_TRUE(attrBase); - auto attr = std::dynamic_pointer_cast<AttributeType>(attrBase); - EXPECT_TRUE(attr); - attr->addReservedDoc(); - for (const auto &docValues : values) { - uint32_t docId = 0; - EXPECT_TRUE(attr->addDoc(docId)); - EXPECT_NE(0u, docId); - for (const auto &value : docValues) { - attr->append(docId, value, 1); - } - attr->commit(); - } - EXPECT_TRUE(mgr.add(attr)); -} - -void -AttributeManagerFixture::buildStringAttribute(const vespalib::string &name, - std::vector<std::vector<vespalib::string>> values) -{ - buildAttribute<StringAttribute, vespalib::string>(name, BasicType::Type::STRING, std::move(values)); -} - -void -AttributeManagerFixture::buildFloatAttribute(const vespalib::string &name, - std::vector<std::vector<double>> values) -{ - buildAttribute<FloatingPointAttribute, double>(name, BasicType::Type::DOUBLE, std::move(values)); -} - -void -AttributeManagerFixture::buildIntegerAttribute(const vespalib::string &name, - BasicType type, - std::vector<std::vector<IAttributeVector::largeint_t>> values) -{ - buildAttribute<IntegerAttribute, IAttributeVector::largeint_t>(name, type, std::move(values)); -} - - -class DummyStateCallback : public GetDocsumsStateCallback -{ -public: - MatchingElements _matching_elements; - - DummyStateCallback(); - void FillSummaryFeatures(GetDocsumsState *, IDocsumEnvironment *) override { } - void FillRankFeatures(GetDocsumsState *, IDocsumEnvironment *) override { } - void ParseLocation(GetDocsumsState *) override { } - std::unique_ptr<MatchingElements> fill_matching_elements(const search::MatchingElementsFields &) override { return std::make_unique<MatchingElements>(_matching_elements); } - ~DummyStateCallback() override { } -}; - -DummyStateCallback::DummyStateCallback() - : GetDocsumsStateCallback(), - _matching_elements() -{ - _matching_elements.add_matching_elements(1, "array", {1}); - _matching_elements.add_matching_elements(3, "array", {0}); - _matching_elements.add_matching_elements(4, "array", {1}); - _matching_elements.add_matching_elements(1, "smap", {1}); - _matching_elements.add_matching_elements(3, "smap", {0}); - _matching_elements.add_matching_elements(4, "smap", {1}); - _matching_elements.add_matching_elements(1, "map", {1}); - _matching_elements.add_matching_elements(3, "map", {0}); - _matching_elements.add_matching_elements(4, "map", {1}); -} - struct AttributeCombinerTest : public ::testing::Test { - AttributeManagerFixture attrs; + MockAttributeManager attrs; std::unique_ptr<IDocsumFieldWriter> writer; - DummyStateCallback stateCallback; + MockStateCallback callback; GetDocsumsState state; std::shared_ptr<search::MatchingElementsFields> _matching_elems_fields; @@ -177,11 +48,31 @@ struct AttributeCombinerTest : public ::testing::Test AttributeCombinerTest::AttributeCombinerTest() : attrs(), writer(), - stateCallback(), - state(stateCallback), + callback(), + state(callback), _matching_elems_fields() { - state._attrCtx = attrs.mgr.createContext(); + attrs.build_string_attribute("array.name", {{"n1.1", "n1.2"}, {"n2"}, {"n3.1", "n3.2"}, {"", "n4.2"}, {}}); + attrs.build_int_attribute("array.val", BasicType::Type::INT8, {{ 10, 11}, {20, 21 }, {30}, { getUndefined<int8_t>(), 41}, {}}); + attrs.build_float_attribute("array.fval", {{ 110.0}, { 120.0, 121.0 }, { 130.0, 131.0}, { getUndefined<double>(), 141.0 }, {}}); + attrs.build_string_attribute("smap.key", {{"k1.1", "k1.2"}, {"k2"}, {"k3.1", "k3.2"}, {"", "k4.2"}, {}}); + attrs.build_string_attribute("smap.value.name", {{"n1.1", "n1.2"}, {"n2"}, {"n3.1", "n3.2"}, {"", "n4.2"}, {}}); + attrs.build_int_attribute("smap.value.val", BasicType::Type::INT8, {{ 10, 11}, {20, 21 }, {30}, { getUndefined<int8_t>(), 41}, {}}); + attrs.build_float_attribute("smap.value.fval", {{ 110.0}, { 120.0, 121.0 }, { 130.0, 131.0}, { getUndefined<double>(), 141.0 }, {}}); + attrs.build_string_attribute("map.key", {{"k1.1", "k1.2"}, {"k2"}, {"k3.1"}, {"", "k4.2"}, {}}); + attrs.build_string_attribute("map.value", {{"n1.1", "n1.2"}, {}, {"n3.1", "n3.2"}, {"", "n4.2"}, {}}); + + callback.add_matching_elements(1, "array", {1}); + callback.add_matching_elements(3, "array", {0}); + callback.add_matching_elements(4, "array", {1}); + callback.add_matching_elements(1, "smap", {1}); + callback.add_matching_elements(3, "smap", {0}); + callback.add_matching_elements(4, "smap", {1}); + callback.add_matching_elements(1, "map", {1}); + callback.add_matching_elements(3, "map", {0}); + callback.add_matching_elements(4, "map", {1}); + + state._attrCtx = attrs.mgr().createContext(); } AttributeCombinerTest::~AttributeCombinerTest() = default; diff --git a/searchsummary/src/tests/docsummary/attributedfw/CMakeLists.txt b/searchsummary/src/tests/docsummary/attributedfw/CMakeLists.txt new file mode 100644 index 00000000000..8bdf30273f2 --- /dev/null +++ b/searchsummary/src/tests/docsummary/attributedfw/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +find_package(GTest REQUIRED) +vespa_add_executable(searchsummary_attributedfw_test_app TEST + SOURCES + attributedfw_test.cpp + DEPENDS + searchsummary + searchsummary_test + GTest::GTest +) +vespa_add_test(NAME searchsummary_attributedfw_test_app COMMAND searchsummary_attributedfw_test_app) diff --git a/searchsummary/src/tests/docsummary/attributedfw/attributedfw_test.cpp b/searchsummary/src/tests/docsummary/attributedfw/attributedfw_test.cpp new file mode 100644 index 00000000000..7bea92ec8f3 --- /dev/null +++ b/searchsummary/src/tests/docsummary/attributedfw/attributedfw_test.cpp @@ -0,0 +1,150 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include <vespa/searchlib/common/matching_elements_fields.h> +#include <vespa/searchsummary/docsummary/attributedfw.h> +#include <vespa/searchsummary/test/mock_attribute_manager.h> +#include <vespa/searchsummary/test/mock_state_callback.h> +#include <vespa/searchsummary/test/slime_value.h> +#include <vespa/vespalib/gtest/gtest.h> + +#include <vespa/log/log.h> +LOG_SETUP("attributedfw_test"); + +using search::MatchingElements; +using search::MatchingElementsFields; +using search::attribute::BasicType; +using search::attribute::CollectionType; +using search::docsummary::AttributeDFWFactory; +using search::docsummary::GetDocsumsState; +using search::docsummary::IDocsumFieldWriter; +using search::docsummary::test::MockAttributeManager; +using search::docsummary::test::MockStateCallback; +using search::docsummary::test::SlimeValue; + +using ElementVector = std::vector<uint32_t>; + +class AttributeDFWTest : public ::testing::Test { +protected: + MockAttributeManager _attrs; + std::unique_ptr<IDocsumFieldWriter> _writer; + MockStateCallback _callback; + GetDocsumsState _state; + std::shared_ptr<search::MatchingElementsFields> _matching_elems_fields; + vespalib::string _field_name; + +public: + AttributeDFWTest() + : _attrs(), + _writer(), + _callback(), + _state(_callback), + _matching_elems_fields(), + _field_name() + { + _attrs.build_string_attribute("array_str", { {"a", "b", "c"}, {} }); + _attrs.build_int_attribute("array_int", BasicType::INT32, { {10, 20, 30}, {} }); + _attrs.build_float_attribute("array_float", { {10.5, 20.5, 30.5}, {} }); + + _attrs.build_string_attribute("wset_str", { {"a", "b", "c"}, {} }, CollectionType::WSET); + _attrs.build_int_attribute("wset_int", BasicType::INT32, { {10, 20, 30}, {} }, CollectionType::WSET); + _attrs.build_float_attribute("wset_float", { {10.5, 20.5, 30.5}, {} }, CollectionType::WSET); + + _state._attrCtx = _attrs.mgr().createContext(); + } + ~AttributeDFWTest() {} + + void setup(const vespalib::string& field_name, bool filter_elements) { + if (filter_elements) { + _matching_elems_fields = std::make_shared<MatchingElementsFields>(); + } + _writer = AttributeDFWFactory::create(_attrs.mgr(), field_name, filter_elements, _matching_elems_fields); + _writer->setIndex(0); + _field_name = field_name; + _state._attributes.resize(1); + _state._attributes[0] = _state._attrCtx->getAttribute(field_name); + } + + void expect_field(const vespalib::string& exp_slime_as_json, uint32_t docid) { + vespalib::Slime act; + vespalib::slime::SlimeInserter inserter(act); + _writer->insertField(docid, nullptr, &_state, search::docsummary::RES_JSONSTRING, inserter); + + SlimeValue exp(exp_slime_as_json); + EXPECT_EQ(exp.slime, act); + } + + void expect_filtered(const ElementVector& matching_elems, const std::string& exp_slime_as_json, uint32_t docid = 1) { + _callback.clear(); + _callback.add_matching_elements(docid, _field_name, matching_elems); + _state._matching_elements = std::unique_ptr<MatchingElements>(); + expect_field(exp_slime_as_json, docid); + } +}; + +TEST_F(AttributeDFWTest, outputs_slime_for_array_of_string) +{ + setup("array_str", false); + expect_field("[ 'a', 'b', 'c' ]", 1); + expect_field("null", 2); +} + +TEST_F(AttributeDFWTest, outputs_slime_for_array_of_int) +{ + setup("array_int", false); + expect_field("[ 10, 20, 30 ]", 1); + expect_field("null", 2); +} + +TEST_F(AttributeDFWTest, outputs_slime_for_array_of_float) +{ + setup("array_float", false); + expect_field("[ 10.5, 20.5, 30.5 ]", 1); + expect_field("null", 2); +} + +TEST_F(AttributeDFWTest, outputs_slime_for_wset_of_string) +{ + setup("wset_str", false); + expect_field("[ {'item':'a', 'weight':1}, {'item':'b', 'weight':1}, {'item':'c', 'weight':1} ]", 1); + expect_field("null", 2); +} + +TEST_F(AttributeDFWTest, outputs_slime_for_wset_of_int) +{ + setup("wset_int", false); + expect_field("[ {'item':10, 'weight':1}, {'item':20, 'weight':1}, {'item':30, 'weight':1} ]", 1); + expect_field("null", 2); +} + +TEST_F(AttributeDFWTest, outputs_slime_for_wset_of_float) +{ + setup("wset_float", false); + expect_field("[ {'item':10.5, 'weight':1}, {'item':20.5, 'weight':1}, {'item':30.5, 'weight':1} ]", 1); + expect_field("null", 2); +} + +TEST_F(AttributeDFWTest, matched_elements_fields_is_populated) +{ + setup("array_str", true); + EXPECT_TRUE(_matching_elems_fields->has_field("array_str")); +} + +TEST_F(AttributeDFWTest, filteres_matched_elements_in_array_attribute) +{ + setup("array_str", true); + expect_filtered({}, "[]"); + expect_filtered({0}, "[ 'a' ]"); + expect_filtered({1, 2}, "[ 'b', 'c' ]"); + expect_filtered({3}, "[]"); +} + +TEST_F(AttributeDFWTest, filteres_matched_elements_in_wset_attribute) +{ + setup("wset_str", true); + expect_filtered({}, "[]"); + expect_filtered({0}, "[ {'item':'a', 'weight':1} ]"); + expect_filtered({1, 2}, "[ {'item':'b', 'weight':1}, {'item':'c', 'weight':1} ]"); + expect_filtered({3}, "[]"); +} + +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchsummary/src/vespa/searchsummary/docsummary/attributedfw.cpp b/searchsummary/src/vespa/searchsummary/docsummary/attributedfw.cpp index 704876f4838..05ba12ddff9 100644 --- a/searchsummary/src/vespa/searchsummary/docsummary/attributedfw.cpp +++ b/searchsummary/src/vespa/searchsummary/docsummary/attributedfw.cpp @@ -9,6 +9,8 @@ #include <vespa/searchlib/attribute/iattributemanager.h> #include <vespa/searchlib/attribute/integerbase.h> #include <vespa/searchlib/attribute/stringbase.h> +#include <vespa/searchlib/common/matching_elements.h> +#include <vespa/searchlib/common/matching_elements_fields.h> #include <vespa/searchlib/tensor/i_tensor_attribute.h> #include <vespa/vespalib/data/slime/slime.h> #include <vespa/vespalib/objects/nbostream.h> @@ -139,12 +141,21 @@ template <typename DataType> class MultiAttrDFW : public AttrDFW { private: bool _is_weighted_set; + bool _filter_elements; + std::shared_ptr<MatchingElementsFields> _matching_elems_fields; public: - explicit MultiAttrDFW(const vespalib::string& attr_name, bool is_weighted_set) + explicit MultiAttrDFW(const vespalib::string& attr_name, bool is_weighted_set, + bool filter_elements, std::shared_ptr<MatchingElementsFields> matching_elems_fields) : AttrDFW(attr_name), - _is_weighted_set(is_weighted_set) - {} + _is_weighted_set(is_weighted_set), + _filter_elements(filter_elements), + _matching_elems_fields(std::move(matching_elems_fields)) + { + if (filter_elements && _matching_elems_fields) { + _matching_elems_fields->add_field(attr_name); + } + } void insertField(uint32_t docid, GetDocsumsState* state, ResType type, Inserter& target) override; }; @@ -202,8 +213,19 @@ MultiAttrDFW<DataType>::insertField(uint32_t docid, GetDocsumsState* state, ResT Cursor &arr = target.insertArray(); std::vector<DataType> elements(entries); entries = std::min(entries, attr.get(docid, elements.data(), entries)); - for (uint32_t i = 0; i < entries; ++i) { - insert_element(elements, i, _is_weighted_set, arr); + + if (_filter_elements) { + const auto& matching_elems = state->get_matching_elements(*_matching_elems_fields) + .get_matching_elements(docid, getAttributeName()); + if (!matching_elems.empty() && matching_elems.back() < entries) { + for (uint32_t id_to_keep : matching_elems) { + insert_element(elements, id_to_keep, _is_weighted_set, arr); + } + } + } else { + for (uint32_t i = 0; i < entries; ++i) { + insert_element(elements, i, _is_weighted_set, arr); + } } } @@ -212,14 +234,17 @@ MultiAttrDFW<DataType>::insertField(uint32_t docid, GetDocsumsState* state, ResT namespace { std::unique_ptr<IDocsumFieldWriter> -create_multi_writer(const IAttributeVector& attr) +create_multi_writer(const IAttributeVector& attr, + bool filter_elements, + std::shared_ptr<MatchingElementsFields> matching_elems_fields) { auto type = attr.getBasicType(); bool is_weighted_set = attr.hasWeightedSetType(); switch (type) { case BasicType::NONE: case BasicType::STRING: { - return std::make_unique<MultiAttrDFW<IAttributeVector::WeightedString>>(attr.getName(), is_weighted_set); + return std::make_unique<MultiAttrDFW<IAttributeVector::WeightedString>>(attr.getName(), is_weighted_set, + filter_elements, std::move(matching_elems_fields)); } case BasicType::BOOL: case BasicType::UINT2: @@ -228,11 +253,13 @@ create_multi_writer(const IAttributeVector& attr) case BasicType::INT16: case BasicType::INT32: case BasicType::INT64: { - return std::make_unique<MultiAttrDFW<IAttributeVector::WeightedInt>>(attr.getName(), is_weighted_set); + return std::make_unique<MultiAttrDFW<IAttributeVector::WeightedInt>>(attr.getName(), is_weighted_set, + filter_elements, std::move(matching_elems_fields)); } case BasicType::FLOAT: case BasicType::DOUBLE: { - return std::make_unique<MultiAttrDFW<IAttributeVector::WeightedFloat>>(attr.getName(), is_weighted_set); + return std::make_unique<MultiAttrDFW<IAttributeVector::WeightedFloat>>(attr.getName(), is_weighted_set, + filter_elements, std::move(matching_elems_fields)); } default: // should not happen @@ -244,7 +271,10 @@ create_multi_writer(const IAttributeVector& attr) } std::unique_ptr<IDocsumFieldWriter> -AttributeDFWFactory::create(IAttributeManager& attr_mgr, const vespalib::string& attr_name) +AttributeDFWFactory::create(IAttributeManager& attr_mgr, + const vespalib::string& attr_name, + bool filter_elements, + std::shared_ptr<MatchingElementsFields> matching_elems_fields) { auto ctx = attr_mgr.createContext(); const auto* attr = ctx->getAttribute(attr_name); @@ -253,7 +283,7 @@ AttributeDFWFactory::create(IAttributeManager& attr_mgr, const vespalib::string& return std::unique_ptr<IDocsumFieldWriter>(); } if (attr->hasMultiValue()) { - return create_multi_writer(*attr); + return create_multi_writer(*attr, filter_elements, std::move(matching_elems_fields)); } else { return std::make_unique<SingleAttrDFW>(attr->getName()); } diff --git a/searchsummary/src/vespa/searchsummary/docsummary/attributedfw.h b/searchsummary/src/vespa/searchsummary/docsummary/attributedfw.h index 03de2cc76b4..55a30f0bb7b 100644 --- a/searchsummary/src/vespa/searchsummary/docsummary/attributedfw.h +++ b/searchsummary/src/vespa/searchsummary/docsummary/attributedfw.h @@ -4,6 +4,8 @@ #include "docsumfieldwriter.h" + +namespace search { class MatchingElementsFields; } namespace search::attribute { class IAttributeVector; } namespace search::docsummary { @@ -13,7 +15,11 @@ namespace search::docsummary { */ class AttributeDFWFactory { public: - static std::unique_ptr<IDocsumFieldWriter> create(IAttributeManager& attr_mgr, const vespalib::string& attr_name); + static std::unique_ptr<IDocsumFieldWriter> create(IAttributeManager& attr_mgr, + const vespalib::string& attr_name, + bool filter_elements = false, + std::shared_ptr<MatchingElementsFields> matching_elems_fields + = std::shared_ptr<MatchingElementsFields>()); }; class AttrDFW : public ISimpleDFW diff --git a/searchsummary/src/vespa/searchsummary/test/CMakeLists.txt b/searchsummary/src/vespa/searchsummary/test/CMakeLists.txt index aea75ffb244..ae4414bb078 100644 --- a/searchsummary/src/vespa/searchsummary/test/CMakeLists.txt +++ b/searchsummary/src/vespa/searchsummary/test/CMakeLists.txt @@ -1,6 +1,7 @@ # Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. vespa_add_library(searchsummary_test OBJECT SOURCES + mock_attribute_manager.cpp AFTER searchsummary_config ) diff --git a/searchsummary/src/vespa/searchsummary/test/mock_attribute_manager.cpp b/searchsummary/src/vespa/searchsummary/test/mock_attribute_manager.cpp new file mode 100644 index 00000000000..bd7307d1624 --- /dev/null +++ b/searchsummary/src/vespa/searchsummary/test/mock_attribute_manager.cpp @@ -0,0 +1,72 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "mock_attribute_manager.h" +#include <vespa/searchlib/attribute/attributefactory.h> +#include <vespa/searchlib/attribute/attributevector.h> +#include <vespa/searchlib/attribute/attributevector.hpp> +#include <vespa/searchlib/attribute/floatbase.h> +#include <vespa/searchlib/attribute/integerbase.h> +#include <vespa/searchlib/attribute/stringbase.h> +#include <cassert> + +using search::attribute::BasicType; +using search::attribute::CollectionType; +using search::attribute::Config; + +namespace search::docsummary::test { + +template <typename AttributeType, typename ValueType> +void +MockAttributeManager::build_attribute(const vespalib::string& name, BasicType type, + search::attribute::CollectionType col_type, + const std::vector<std::vector<ValueType>>& values) +{ + Config cfg(type, col_type); + auto attr_base = AttributeFactory::createAttribute(name, cfg); + assert(attr_base); + auto attr = std::dynamic_pointer_cast<AttributeType>(attr_base); + assert(attr); + attr->addReservedDoc(); + for (const auto& docValues : values) { + uint32_t docId = 0; + attr->addDoc(docId); + for (const auto& value : docValues) { + attr->append(docId, value, 1); + } + attr->commit(); + } + _mgr.add(attr); +} + +MockAttributeManager::MockAttributeManager() + : _mgr() +{ +} + +MockAttributeManager::~MockAttributeManager() = default; + +void +MockAttributeManager::build_string_attribute(const vespalib::string& name, + const std::vector<std::vector<vespalib::string>>& values, + CollectionType col_type) +{ + build_attribute<StringAttribute, vespalib::string>(name, BasicType::Type::STRING, col_type, values); +} + +void +MockAttributeManager::build_float_attribute(const vespalib::string& name, + const std::vector<std::vector<double>>& values, + CollectionType col_type) +{ + build_attribute<FloatingPointAttribute, double>(name, BasicType::Type::DOUBLE, col_type, values); +} + +void +MockAttributeManager::build_int_attribute(const vespalib::string& name, BasicType type, + const std::vector<std::vector<int64_t>>& values, + CollectionType col_type) +{ + build_attribute<IntegerAttribute, int64_t>(name, type, col_type, values); +} + +} diff --git a/searchsummary/src/vespa/searchsummary/test/mock_attribute_manager.h b/searchsummary/src/vespa/searchsummary/test/mock_attribute_manager.h new file mode 100644 index 00000000000..a7e425e50b6 --- /dev/null +++ b/searchsummary/src/vespa/searchsummary/test/mock_attribute_manager.h @@ -0,0 +1,37 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include <vespa/searchcommon/attribute/basictype.h> +#include <vespa/searchlib/attribute/attributemanager.h> + +namespace search::docsummary::test { + +/** + * Class used to build attributes and populate a manager for testing. + */ +class MockAttributeManager { +private: + AttributeManager _mgr; + + template <typename AttributeType, typename ValueType> + void build_attribute(const vespalib::string& name, search::attribute::BasicType type, + search::attribute::CollectionType col_type, + const std::vector<std::vector<ValueType>>& values); + +public: + MockAttributeManager(); + ~MockAttributeManager(); + AttributeManager& mgr() { return _mgr; } + + void build_string_attribute(const vespalib::string& name, + const std::vector<std::vector<vespalib::string>>& values, + search::attribute::CollectionType col_type = search::attribute::CollectionType::ARRAY); + void build_float_attribute(const vespalib::string& name, + const std::vector<std::vector<double>>& values, + search::attribute::CollectionType col_type = search::attribute::CollectionType::ARRAY); + void build_int_attribute(const vespalib::string& name, search::attribute::BasicType type, + const std::vector<std::vector<int64_t>>& values, + search::attribute::CollectionType col_type = search::attribute::CollectionType::ARRAY); + +}; + +} diff --git a/searchsummary/src/vespa/searchsummary/test/mock_state_callback.h b/searchsummary/src/vespa/searchsummary/test/mock_state_callback.h new file mode 100644 index 00000000000..b3ee405c856 --- /dev/null +++ b/searchsummary/src/vespa/searchsummary/test/mock_state_callback.h @@ -0,0 +1,35 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include <vespa/searchlib/common/matching_elements.h> +#include <vespa/searchsummary/docsummary/docsumstate.h> + +namespace search::docsummary::test { + +class MockStateCallback : public GetDocsumsStateCallback { +private: + MatchingElements _matching_elems; + +public: + MockStateCallback() + : GetDocsumsStateCallback(), + _matching_elems() + { + } + ~MockStateCallback() override { } + void FillSummaryFeatures(GetDocsumsState*, IDocsumEnvironment*) override { } + void FillRankFeatures(GetDocsumsState*, IDocsumEnvironment*) override { } + void ParseLocation(GetDocsumsState*) override { } + std::unique_ptr<MatchingElements> fill_matching_elements(const search::MatchingElementsFields&) override { + return std::make_unique<MatchingElements>(_matching_elems); + } + + void add_matching_elements(uint32_t docid, const vespalib::string& field_name, + const std::vector<uint32_t>& elements) { + _matching_elems.add_matching_elements(docid, field_name, elements); + } + void clear() { + _matching_elems = MatchingElements(); + } +}; + +} |