diff options
author | Henning Baldersheim <balder@yahoo-inc.com> | 2020-03-19 15:30:19 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-19 15:30:19 +0100 |
commit | 19bbaf872b649b3ce13809f5f9c40af065b28fee (patch) | |
tree | b440fa894d98e38c6bbbebdbfd74227c2b056fb4 | |
parent | b54b22e44a661f84882f581c5f82d248c4d54104 (diff) | |
parent | f2d28cf4c1b8579b58e3ae506fc62970be7fb254 (diff) |
Merge pull request #12618 from vespa-engine/balder/use-fast-map-for-few-elements
Balder/use fast map for few elements.
-rw-r--r-- | searchlib/src/tests/features/prod_features.cpp | 10 | ||||
-rw-r--r-- | searchlib/src/vespa/searchlib/features/dotproductfeature.cpp | 86 |
2 files changed, 90 insertions, 6 deletions
diff --git a/searchlib/src/tests/features/prod_features.cpp b/searchlib/src/tests/features/prod_features.cpp index 863bc4d9f07..64a999906d8 100644 --- a/searchlib/src/tests/features/prod_features.cpp +++ b/searchlib/src/tests/features/prod_features.cpp @@ -1262,10 +1262,12 @@ Test::testDotProduct() assertDotProduct(17, "(0:1,3:4,50:97)", 1, "sint", "arrfloat"); // attribute override assertDotProduct(0, "(0:1,3:4,50:97)", 1, "sint", "arrfloat_non_existing"); // incorrect attribute override } - verifyCorrectDotProductExecutor(_factory, "wsstr", "{a:1}", "search::features::dotproduct::wset::(anonymous namespace)::DotProductExecutorByEnum"); - verifyCorrectDotProductExecutor(_factory, "wsstr", "{unknown:1}", "search::features::SingleZeroValueExecutor"); - verifyCorrectDotProductExecutor(_factory, "wsint", "{1:1}", "search::features::dotproduct::wset::DotProductExecutor<search::MultiValueNumericAttribute<search::IntegerAttributeTemplate<int>, search::multivalue::WeightedValue<int> > >"); - verifyCorrectDotProductExecutor(_factory, "wsint", "{}", "search::features::SingleZeroValueExecutor"); + TEST_DO(verifyCorrectDotProductExecutor(_factory, "wsstr", "{a:1,b:2}", "search::features::dotproduct::wset::(anonymous namespace)::DotProductExecutorByEnum")); + TEST_DO(verifyCorrectDotProductExecutor(_factory, "wsstr", "{a:1}", "search::features::dotproduct::wset::(anonymous namespace)::SingleDotProductExecutorByEnum")); + TEST_DO(verifyCorrectDotProductExecutor(_factory, "wsstr", "{unknown:1}", "search::features::SingleZeroValueExecutor")); + TEST_DO(verifyCorrectDotProductExecutor(_factory, "wsint", "{1:1, 2:3}", "search::features::dotproduct::wset::DotProductExecutor<search::MultiValueNumericAttribute<search::IntegerAttributeTemplate<int>, search::multivalue::WeightedValue<int> > >")); + TEST_DO(verifyCorrectDotProductExecutor(_factory, "wsint", "{1:1}", "search::features::dotproduct::wset::(anonymous namespace)::SingleDotProductExecutorByValue<search::MultiValueNumericAttribute<search::IntegerAttributeTemplate<int>, search::multivalue::WeightedValue<int> > >")); + TEST_DO(verifyCorrectDotProductExecutor(_factory, "wsint", "{}", "search::features::SingleZeroValueExecutor")); } diff --git a/searchlib/src/vespa/searchlib/features/dotproductfeature.cpp b/searchlib/src/vespa/searchlib/features/dotproductfeature.cpp index 1072607aa8a..811a318682b 100644 --- a/searchlib/src/vespa/searchlib/features/dotproductfeature.cpp +++ b/searchlib/src/vespa/searchlib/features/dotproductfeature.cpp @@ -146,7 +146,7 @@ DotProductExecutor<A>::getAttributeValues(uint32_t docId, const AT * & values) namespace { -class DotProductExecutorByEnum : public fef::FeatureExecutor { +class DotProductExecutorByEnum final : public fef::FeatureExecutor { public: using V = VectorBase<EnumHandle, EnumHandle, feature_t>; private: @@ -182,7 +182,8 @@ DotProductExecutorByEnum::DotProductExecutorByEnum(const IWeightedIndexVector * DotProductExecutorByEnum::~DotProductExecutorByEnum() = default; -void DotProductExecutorByEnum::execute(uint32_t docId) { +void +DotProductExecutorByEnum::execute(uint32_t docId) { feature_t val = 0; const IWeightedIndexVector::WeightedIndex *values(nullptr); uint32_t sz = _attribute->getEnumHandles(docId, values); @@ -195,6 +196,55 @@ void DotProductExecutorByEnum::execute(uint32_t docId) { outputs().set_number(0, val); } +class SingleDotProductExecutorByEnum final : public fef::FeatureExecutor { +public: + SingleDotProductExecutorByEnum(const IWeightedIndexVector * attribute, EnumHandle key, feature_t value) + : _attribute(attribute), + _key(key), + _value(value) + {} + + void execute(uint32_t docId) override { + const IWeightedIndexVector::WeightedIndex *values(nullptr); + uint32_t sz = _attribute->getEnumHandles(docId, values); + for (size_t i = 0; i < sz; ++i) { + if (values[i].value().ref() == _key) { + outputs().set_number(0, values[i].weight()*_value); + return; + } + } + outputs().set_number(0, 0); + } +private: + const IWeightedIndexVector * _attribute; + EnumHandle _key; + feature_t _value; +}; + +template <typename A> +class SingleDotProductExecutorByValue final : public fef::FeatureExecutor { +public: + SingleDotProductExecutorByValue(const A * attribute, multivalue::WeightedValue<typename A::BaseType> keyValue) + : _attribute(attribute), + _keyValue(keyValue) + {} + + void execute(uint32_t docId) override { + const multivalue::WeightedValue<typename A::BaseType> *values(nullptr); + uint32_t sz = _attribute->getRawValues(docId, values); + for (size_t i = 0; i < sz; ++i) { + if (values[i].value() == _keyValue.value()) { + outputs().set_number(0, values[i].weight()*_keyValue.weight()); + return; + } + } + outputs().set_number(0, 0); + } +private: + const A * _attribute; + multivalue::WeightedValue<typename A::BaseType> _keyValue; +}; + } } @@ -572,6 +622,27 @@ createForDirectArray(const IAttributeVector * attribute, return createForDirectArrayImpl<A>(attribute, arguments.values, arguments.indexes, stash); } +template<typename T> +size_t extractSize(const dotproduct::wset::IntegerVectorT<T> & v) { + return v.getVector().size(); +} + +template<typename T> +multivalue::WeightedValue<T> extractElem(const dotproduct::wset::IntegerVectorT<T> & v, size_t idx) { + const auto & pair = v.getVector()[idx]; + return multivalue::WeightedValue<T>(pair.first, pair.second); +} + +template<typename T> +size_t extractSize(const std::unique_ptr<dotproduct::wset::IntegerVectorT<T>> & v) { + return extractSize(*v); +} + +template<typename T> +multivalue::WeightedValue<T> extractElem(const std::unique_ptr<dotproduct::wset::IntegerVectorT<T>> & v, size_t idx) { + return extractElem(*v, idx); +} + template <typename A, typename V> FeatureExecutor & createForDirectWSetImpl(const IAttributeVector * attribute, V && vector, vespalib::Stash & stash) @@ -584,6 +655,9 @@ createForDirectWSetImpl(const IAttributeVector * attribute, V && vector, vespali if (!attribute->isImported() && (iattr != nullptr) && supportsGetRawValues<A, VT>(*iattr)) { auto * exactA = dynamic_cast<const ExactA *>(iattr); if (exactA != nullptr) { + if (extractSize(vector) == 1) { + return stash.create<SingleDotProductExecutorByValue<ExactA>>(exactA, extractElem(vector, 0ul)); + } return stash.create<DotProductExecutor<ExactA>>(exactA, std::forward<V>(vector)); } return stash.create<DotProductExecutor<A>>(iattr, std::forward<V>(vector)); @@ -642,6 +716,10 @@ createFromObject(const IAttributeVector * attribute, const fef::Anything & objec } const auto * getEnumHandles = dynamic_cast<const IWeightedIndexVector *>(attribute); if (supportsGetEnumHandles(getEnumHandles)) { + if (vector.getVector().size() == 1) { + const auto & elem = vector.getVector()[0]; + return stash.create<SingleDotProductExecutorByEnum>(getEnumHandles, elem.first, elem.second); + } return stash.create<DotProductExecutorByEnum>(getEnumHandles, vector); } return stash.create<DotProductExecutorByCopy<EnumVector, WeightedEnumContent>>(attribute, vector); @@ -732,6 +810,10 @@ createTypedWsetExecutor(const IAttributeVector * attribute, const Property & pro vector->syncMap(); auto * getEnumHandles = dynamic_cast<const IWeightedIndexVector *>(attribute); if (supportsGetEnumHandles(getEnumHandles)) { + if (vector->getVector().size() == 1) { + const auto & elem = vector->getVector()[0]; + return stash.create<SingleDotProductExecutorByEnum>(getEnumHandles, elem.first, elem.second); + } return stash.create<DotProductExecutorByEnum>(getEnumHandles, std::move(vector)); } return stash.create<DotProductExecutorByCopy<EnumVector, WeightedEnumContent>>(attribute, std::move(vector)); |