aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenning Baldersheim <balder@yahoo-inc.com>2020-03-19 15:30:19 +0100
committerGitHub <noreply@github.com>2020-03-19 15:30:19 +0100
commit19bbaf872b649b3ce13809f5f9c40af065b28fee (patch)
treeb440fa894d98e38c6bbbebdbfd74227c2b056fb4
parentb54b22e44a661f84882f581c5f82d248c4d54104 (diff)
parentf2d28cf4c1b8579b58e3ae506fc62970be7fb254 (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.cpp10
-rw-r--r--searchlib/src/vespa/searchlib/features/dotproductfeature.cpp86
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));