From 90f16b7689e19faef111f127908a513bb6990bb1 Mon Sep 17 00:00:00 2001 From: Tor Egge Date: Mon, 10 Sep 2018 13:42:42 +0000 Subject: Rename AttributeKeyedNode to AttributeMapLookupNode. --- .../attributenode/attribute_node_test.cpp | 6 +- .../src/vespa/searchlib/aggregation/modifiers.cpp | 4 +- .../src/vespa/searchlib/expression/CMakeLists.txt | 2 +- .../searchlib/expression/attribute_keyed_node.cpp | 412 --------------------- .../searchlib/expression/attribute_keyed_node.h | 45 --- .../expression/attribute_map_lookup_node.cpp | 412 +++++++++++++++++++++ .../expression/attribute_map_lookup_node.h | 45 +++ 7 files changed, 463 insertions(+), 463 deletions(-) delete mode 100644 searchlib/src/vespa/searchlib/expression/attribute_keyed_node.cpp delete mode 100644 searchlib/src/vespa/searchlib/expression/attribute_keyed_node.h create mode 100644 searchlib/src/vespa/searchlib/expression/attribute_map_lookup_node.cpp create mode 100644 searchlib/src/vespa/searchlib/expression/attribute_map_lookup_node.h (limited to 'searchlib') diff --git a/searchlib/src/tests/expression/attributenode/attribute_node_test.cpp b/searchlib/src/tests/expression/attributenode/attribute_node_test.cpp index c92b5fc4808..b2e4bd41680 100644 --- a/searchlib/src/tests/expression/attributenode/attribute_node_test.cpp +++ b/searchlib/src/tests/expression/attributenode/attribute_node_test.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include @@ -31,7 +31,7 @@ using search::attribute::Config; using search::attribute::IAttributeVector; using search::attribute::getUndefined; using search::expression::AttributeNode; -using search::expression::AttributeKeyedNode; +using search::expression::AttributeMapLookupNode; using search::expression::EnumResultNode; using search::expression::EnumResultNodeVector; using search::expression::FloatResultNode; @@ -220,7 +220,7 @@ Fixture::makeNode(const vespalib::string &attributeName, bool useEnumOptimizatio if (attributeName.find('{') == vespalib::string::npos) { node = std::make_unique(attributeName); } else { - node = std::make_unique(attributeName); + node = std::make_unique(attributeName); } if (useEnumOptimization) { node->useEnumOptimization(); diff --git a/searchlib/src/vespa/searchlib/aggregation/modifiers.cpp b/searchlib/src/vespa/searchlib/aggregation/modifiers.cpp index fe71484c4e6..0b91d37862d 100644 --- a/searchlib/src/vespa/searchlib/aggregation/modifiers.cpp +++ b/searchlib/src/vespa/searchlib/aggregation/modifiers.cpp @@ -4,7 +4,7 @@ #include "grouping.h" #include #include -#include +#include #include using namespace search::expression; @@ -72,7 +72,7 @@ Attribute2AttributeKeyed::getReplacementNode(const AttributeNode &attributeNode) if (attributeNode.isKeyed() || lBracePos == vespalib::string::npos) { return std::unique_ptr(); } else { - return std::make_unique(attributeName); + return std::make_unique(attributeName); } } diff --git a/searchlib/src/vespa/searchlib/expression/CMakeLists.txt b/searchlib/src/vespa/searchlib/expression/CMakeLists.txt index 944bc6f63df..652fa5a3b01 100644 --- a/searchlib/src/vespa/searchlib/expression/CMakeLists.txt +++ b/searchlib/src/vespa/searchlib/expression/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. vespa_add_library(searchlib_expression OBJECT SOURCES - attribute_keyed_node.cpp + attribute_map_lookup_node.cpp attributenode.cpp attributeresult.cpp enumattributeresult.cpp diff --git a/searchlib/src/vespa/searchlib/expression/attribute_keyed_node.cpp b/searchlib/src/vespa/searchlib/expression/attribute_keyed_node.cpp deleted file mode 100644 index da6ed363b17..00000000000 --- a/searchlib/src/vespa/searchlib/expression/attribute_keyed_node.cpp +++ /dev/null @@ -1,412 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#include "attribute_keyed_node.h" -#include -#include -#include -#include -#include - -using search::attribute::AttributeContent; -using search::attribute::IAttributeVector; -using search::attribute::BasicType; -using search::attribute::getUndefined; -using EnumHandle = IAttributeVector::EnumHandle; - -namespace search::expression { - -class AttributeKeyedNode::KeyHandler -{ -protected: - const IAttributeVector &_attribute; - - KeyHandler(const IAttributeVector &attribute) - : _attribute(attribute) - { - } -public: - static uint32_t noKeyIdx() { return std::numeric_limits::max(); } - virtual ~KeyHandler() = default; - virtual uint32_t handle(DocId docId) = 0; -}; - -namespace { - -vespalib::string indirectKeyMarker("attribute("); - -class BadKeyHandler : public AttributeKeyedNode::KeyHandler -{ -public: - BadKeyHandler(const IAttributeVector &attribute) - : KeyHandler(attribute) - { - } - uint32_t handle(DocId) override { return noKeyIdx(); } -}; - -template -KeyType convertKey(const IAttributeVector &, const vespalib::string &key) -{ - KeyType ret; - vespalib::asciistream is(key); - is >> ret; - return ret; -} - -template <> -vespalib::string convertKey(const IAttributeVector &, const vespalib::string &key) -{ - return key; -} - -template <> -EnumHandle convertKey(const IAttributeVector &attribute, const vespalib::string &key) -{ - EnumHandle ret; - if (!attribute.findEnum(key.c_str(), ret)) { - ret = EnumHandle(); - } - return ret; -} - -template -class KeyHandlerT : public AttributeKeyedNode::KeyHandler -{ - AttributeContent _keys; - KeyType _key; - -public: - KeyHandlerT(const IAttributeVector &attribute, const vespalib::string &key) - : KeyHandler(attribute), - _keys(), - _key(convertKey(attribute, key)) - { - } - ~KeyHandlerT() override; - uint32_t handle(DocId docId) override { - _keys.fill(_attribute, docId); - for (uint32_t i = 0; i < _keys.size(); ++i) { - if (_key == _keys[i]) { - return i; - } - } - return noKeyIdx(); - } -}; - -template -KeyHandlerT::~KeyHandlerT() -{ -} - -using IntegerKeyHandler = KeyHandlerT; -using FloatKeyHandler = KeyHandlerT; -using StringKeyHandler = KeyHandlerT; -using EnumKeyHandler = KeyHandlerT; - -template -bool -matchingKey(T lhs, T rhs) -{ - return lhs == rhs; -} - -template <> -bool -matchingKey(const char *lhs, const char *rhs) -{ - return (strcmp(lhs, rhs) == 0); -} - -template -class IndirectKeyHandlerT : public AttributeKeyedNode::KeyHandler -{ - const IAttributeVector &_keySourceAttribute; - AttributeContent _keys; - -public: - IndirectKeyHandlerT(const IAttributeVector &attribute, const IAttributeVector &keySourceAttribute) - : KeyHandler(attribute), - _keySourceAttribute(keySourceAttribute), - _keys() - { - } - ~IndirectKeyHandlerT() override; - uint32_t handle(DocId docId) override { - T key = T(); - _keySourceAttribute.get(docId, &key, 1); - _keys.fill(_attribute, docId); - for (uint32_t i = 0; i < _keys.size(); ++i) { - if (matchingKey(key, _keys[i])) { - return i; - } - } - return noKeyIdx(); - } -}; - -template -IndirectKeyHandlerT::~IndirectKeyHandlerT() -{ -} - -using IndirectIntegerKeyHandler = IndirectKeyHandlerT; -using IndirectFloatKeyHandler = IndirectKeyHandlerT; -using IndirectStringKeyHandler = IndirectKeyHandlerT; - -class ValueHandler : public AttributeNode::Handler -{ -protected: - std::unique_ptr _keyHandler; - const IAttributeVector &_attribute; - ValueHandler(std::unique_ptr keyHandler, const IAttributeVector &attribute) - : _keyHandler(std::move(keyHandler)), - _attribute(attribute) - { - } -}; - -template -class ValueHandlerT : public ValueHandler -{ - AttributeContent _values; - ResultNodeType &_result; - T _undefinedValue; -public: - ValueHandlerT(std::unique_ptr keyHandler, const IAttributeVector &attribute, ResultNodeType &result, T undefinedValue) - : ValueHandler(std::move(keyHandler), attribute), - _values(), - _result(result), - _undefinedValue(undefinedValue) - { - } - void handle(const AttributeResult & r) override { - uint32_t docId = r.getDocId(); - uint32_t keyIdx = _keyHandler->handle(docId); - if (keyIdx != AttributeKeyedNode::KeyHandler::noKeyIdx()) { - _values.fill(_attribute, docId); - if (keyIdx < _values.size()) { - _result = _values[keyIdx]; - return; - } - } - _result = _undefinedValue; - } -}; - -template -using IntegerValueHandler = ValueHandlerT; -using FloatValueHandler = ValueHandlerT; -using StringValueHandler = ValueHandlerT; -using EnumValueHandler = ValueHandlerT; - -const IAttributeVector *findAttribute(const search::attribute::IAttributeContext &attrCtx, bool useEnumOptimization, const vespalib::string &name) -{ - const IAttributeVector *attribute = useEnumOptimization ? attrCtx.getAttributeStableEnum(name) : attrCtx.getAttribute(name); - if (attribute == nullptr) { - throw std::runtime_error(vespalib::make_string("Failed locating attribute vector '%s'", name.c_str())); - } - return attribute; -} - -IAttributeVector::largeint_t getUndefinedValue(BasicType::Type basicType) -{ - switch (basicType) { - case BasicType::INT8: - return getUndefined(); - case BasicType::INT16: - return getUndefined(); - case BasicType::INT32: - return getUndefined(); - case BasicType::INT64: - return getUndefined(); - break; - default: - return 0; - } -} - -} - -AttributeKeyedNode::AttributeKeyedNode() - : AttributeNode(), - _keyAttributeName(), - _valueAttributeName(), - _key(), - _keySourceAttributeName(), - _keyAttribute(nullptr), - _keySourceAttribute(nullptr) -{ -} - -AttributeKeyedNode::AttributeKeyedNode(const AttributeKeyedNode &) = default; - -AttributeKeyedNode::AttributeKeyedNode(vespalib::stringref name) - : AttributeNode(name), - _keyAttributeName(), - _valueAttributeName(), - _key(), - _keySourceAttributeName(), - _keyAttribute(nullptr), - _keySourceAttribute(nullptr) -{ - setupAttributeNames(); -} - -AttributeKeyedNode::~AttributeKeyedNode() = default; - -AttributeKeyedNode & -AttributeKeyedNode::operator=(const AttributeKeyedNode &rhs) = default; - -void -AttributeKeyedNode::setupAttributeNames() -{ - vespalib::asciistream keyName; - vespalib::asciistream valueName; - auto leftBracePos = _attributeName.find('{'); - auto baseName = _attributeName.substr(0, leftBracePos); - auto rightBracePos = _attributeName.rfind('}'); - keyName << baseName << ".key"; - valueName << baseName << ".value" << _attributeName.substr(rightBracePos + 1); - _keyAttributeName = keyName.str(); - _valueAttributeName = valueName.str(); - if (rightBracePos != vespalib::string::npos && rightBracePos > leftBracePos) { - if (_attributeName[leftBracePos + 1] == '"' && _attributeName[rightBracePos - 1] == '"') { - _key = _attributeName.substr(leftBracePos + 2, rightBracePos - leftBracePos - 3); - } else if (_attributeName.substr(leftBracePos + 1, indirectKeyMarker.size()) == indirectKeyMarker && _attributeName[rightBracePos - 1] == ')') { - auto startPos = leftBracePos + 1 + indirectKeyMarker.size(); - _keySourceAttributeName = _attributeName.substr(startPos, rightBracePos - 1 - startPos); - } - } -} - -template -void -AttributeKeyedNode::prepareIntValues(std::unique_ptr keyHandler, const IAttributeVector &attribute, IAttributeVector::largeint_t undefinedValue) -{ - auto resultNode = std::make_unique(); - _handler = std::make_unique>(std::move(keyHandler), attribute, *resultNode, undefinedValue); - setResultType(std::move(resultNode)); -} - -std::unique_ptr -AttributeKeyedNode::makeKeyHandlerHelper() -{ - const IAttributeVector &attribute = *_keyAttribute; - if (_keySourceAttribute != nullptr) { - const IAttributeVector &keySourceAttribute = *_keySourceAttribute; - if (attribute.isIntegerType() && keySourceAttribute.isIntegerType()) { - return std::make_unique(attribute, keySourceAttribute); - } else if (attribute.isFloatingPointType() && keySourceAttribute.isFloatingPointType()) { - return std::make_unique(attribute, keySourceAttribute); - } else if (attribute.isStringType() && keySourceAttribute.isStringType()) { - return std::make_unique(attribute, keySourceAttribute); - } else { - return std::make_unique(attribute); - } - } - if (attribute.hasEnum() && _useEnumOptimization) { - return std::make_unique(attribute, _key); - } else if (attribute.isIntegerType()) { - return std::make_unique(attribute, _key); - } else if (attribute.isFloatingPointType()) { - return std::make_unique(attribute, _key); - } else if (attribute.isStringType()) { - return std::make_unique(attribute, _key); - } else { - return std::make_unique(attribute); - } -} - -std::unique_ptr -AttributeKeyedNode::makeKeyHandler() -{ - try { - return makeKeyHandlerHelper(); - } catch (const vespalib::IllegalArgumentException &) { - return std::make_unique(*_keyAttribute); - } -} - -void -AttributeKeyedNode::onPrepare(bool preserveAccurateTypes) -{ - auto keyHandler = makeKeyHandler(); - const IAttributeVector * attribute = _scratchResult->getAttribute(); - if (attribute != nullptr) { - BasicType::Type basicType = attribute->getBasicType(); - if (attribute->isIntegerType()) { - IAttributeVector::largeint_t undefinedValue = getUndefinedValue(basicType); - if (preserveAccurateTypes) { - switch (basicType) { - case BasicType::INT8: - prepareIntValues(std::move(keyHandler), *attribute, undefinedValue); - break; - case BasicType::INT16: - prepareIntValues(std::move(keyHandler), *attribute, undefinedValue); - break; - case BasicType::INT32: - prepareIntValues(std::move(keyHandler), *attribute, undefinedValue); - break; - case BasicType::INT64: - prepareIntValues(std::move(keyHandler), *attribute, undefinedValue); - break; - default: - throw std::runtime_error("This is no valid integer attribute " + attribute->getName()); - break; - } - } else { - prepareIntValues(std::move(keyHandler), *attribute, undefinedValue); - } - } else if (attribute->isFloatingPointType()) { - auto resultNode = std::make_unique(); - _handler = std::make_unique(std::move(keyHandler), *attribute, *resultNode, getUndefined()); - setResultType(std::move(resultNode)); - } else if (attribute->isStringType()) { - if (_useEnumOptimization) { - auto resultNode = std::make_unique(); - _handler = std::make_unique(std::move(keyHandler), *attribute, *resultNode, EnumHandle()); - setResultType(std::move(resultNode)); - } else { - auto resultNode = std::make_unique(); - _handler = std::make_unique(std::move(keyHandler), *attribute, *resultNode, ""); - setResultType(std::move(resultNode)); - } - } else { - throw std::runtime_error(vespalib::make_string("Can not deduce correct resultclass for attribute vector '%s'", - attribute->getName().c_str())); - } - } -} - -void -AttributeKeyedNode::cleanup() -{ - _keyAttribute = nullptr; - _keySourceAttribute = nullptr; - AttributeNode::cleanup(); -} - -void -AttributeKeyedNode::wireAttributes(const search::attribute::IAttributeContext &attrCtx) -{ - auto valueAttribute = findAttribute(attrCtx, _useEnumOptimization, _valueAttributeName); - _hasMultiValue = false; - _scratchResult = std::make_unique(valueAttribute, 0); - _keyAttribute = findAttribute(attrCtx, _useEnumOptimization, _keyAttributeName); - if (!_keySourceAttributeName.empty()) { - _keySourceAttribute = findAttribute(attrCtx, false, _keySourceAttributeName); - } -} - -void -AttributeKeyedNode::visitMembers(vespalib::ObjectVisitor &visitor) const -{ - AttributeNode::visitMembers(visitor); - visit(visitor, "keyAttributeName", _keyAttributeName); - visit(visitor, "keySourceAttributeName", _keySourceAttributeName); - visit(visitor, "valueAttributeName", _valueAttributeName); - visit(visitor, "key", _key); -} - -} diff --git a/searchlib/src/vespa/searchlib/expression/attribute_keyed_node.h b/searchlib/src/vespa/searchlib/expression/attribute_keyed_node.h deleted file mode 100644 index e2cf8943aae..00000000000 --- a/searchlib/src/vespa/searchlib/expression/attribute_keyed_node.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#pragma once - -#include "attributenode.h" - -namespace search::expression { - -/** - * Extract map value from attribute for the map key specified in the - * grouping expression. - */ -class AttributeKeyedNode : public AttributeNode -{ -public: - using IAttributeVector = search::attribute::IAttributeVector; - class KeyHandler; -private: - vespalib::string _keyAttributeName; - vespalib::string _valueAttributeName; - vespalib::string _key; - vespalib::string _keySourceAttributeName; - const IAttributeVector *_keyAttribute; - const IAttributeVector *_keySourceAttribute; - - void setupAttributeNames(); - template - void prepareIntValues(std::unique_ptr keyHandler, const IAttributeVector &attribute, IAttributeVector::largeint_t undefinedValue); - std::unique_ptr makeKeyHandlerHelper(); - std::unique_ptr makeKeyHandler(); - void cleanup() override; - void wireAttributes(const search::attribute::IAttributeContext & attrCtx) override; - void onPrepare(bool preserveAccurateTypes) override; -public: - AttributeKeyedNode(); - AttributeKeyedNode(vespalib::stringref name); - AttributeKeyedNode(const AttributeKeyedNode &); - AttributeKeyedNode(AttributeKeyedNode &&) = delete; - ~AttributeKeyedNode() override; - AttributeKeyedNode &operator=(const AttributeKeyedNode &rhs); - AttributeKeyedNode &operator=(AttributeKeyedNode &&rhs) = delete; - void visitMembers(vespalib::ObjectVisitor &visitor) const override; - bool isKeyed() const override { return true; } -}; - -} diff --git a/searchlib/src/vespa/searchlib/expression/attribute_map_lookup_node.cpp b/searchlib/src/vespa/searchlib/expression/attribute_map_lookup_node.cpp new file mode 100644 index 00000000000..f4593552a47 --- /dev/null +++ b/searchlib/src/vespa/searchlib/expression/attribute_map_lookup_node.cpp @@ -0,0 +1,412 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "attribute_map_lookup_node.h" +#include +#include +#include +#include +#include + +using search::attribute::AttributeContent; +using search::attribute::IAttributeVector; +using search::attribute::BasicType; +using search::attribute::getUndefined; +using EnumHandle = IAttributeVector::EnumHandle; + +namespace search::expression { + +class AttributeMapLookupNode::KeyHandler +{ +protected: + const IAttributeVector &_attribute; + + KeyHandler(const IAttributeVector &attribute) + : _attribute(attribute) + { + } +public: + static uint32_t noKeyIdx() { return std::numeric_limits::max(); } + virtual ~KeyHandler() = default; + virtual uint32_t handle(DocId docId) = 0; +}; + +namespace { + +vespalib::string indirectKeyMarker("attribute("); + +class BadKeyHandler : public AttributeMapLookupNode::KeyHandler +{ +public: + BadKeyHandler(const IAttributeVector &attribute) + : KeyHandler(attribute) + { + } + uint32_t handle(DocId) override { return noKeyIdx(); } +}; + +template +KeyType convertKey(const IAttributeVector &, const vespalib::string &key) +{ + KeyType ret; + vespalib::asciistream is(key); + is >> ret; + return ret; +} + +template <> +vespalib::string convertKey(const IAttributeVector &, const vespalib::string &key) +{ + return key; +} + +template <> +EnumHandle convertKey(const IAttributeVector &attribute, const vespalib::string &key) +{ + EnumHandle ret; + if (!attribute.findEnum(key.c_str(), ret)) { + ret = EnumHandle(); + } + return ret; +} + +template +class KeyHandlerT : public AttributeMapLookupNode::KeyHandler +{ + AttributeContent _keys; + KeyType _key; + +public: + KeyHandlerT(const IAttributeVector &attribute, const vespalib::string &key) + : KeyHandler(attribute), + _keys(), + _key(convertKey(attribute, key)) + { + } + ~KeyHandlerT() override; + uint32_t handle(DocId docId) override { + _keys.fill(_attribute, docId); + for (uint32_t i = 0; i < _keys.size(); ++i) { + if (_key == _keys[i]) { + return i; + } + } + return noKeyIdx(); + } +}; + +template +KeyHandlerT::~KeyHandlerT() +{ +} + +using IntegerKeyHandler = KeyHandlerT; +using FloatKeyHandler = KeyHandlerT; +using StringKeyHandler = KeyHandlerT; +using EnumKeyHandler = KeyHandlerT; + +template +bool +matchingKey(T lhs, T rhs) +{ + return lhs == rhs; +} + +template <> +bool +matchingKey(const char *lhs, const char *rhs) +{ + return (strcmp(lhs, rhs) == 0); +} + +template +class IndirectKeyHandlerT : public AttributeMapLookupNode::KeyHandler +{ + const IAttributeVector &_keySourceAttribute; + AttributeContent _keys; + +public: + IndirectKeyHandlerT(const IAttributeVector &attribute, const IAttributeVector &keySourceAttribute) + : KeyHandler(attribute), + _keySourceAttribute(keySourceAttribute), + _keys() + { + } + ~IndirectKeyHandlerT() override; + uint32_t handle(DocId docId) override { + T key = T(); + _keySourceAttribute.get(docId, &key, 1); + _keys.fill(_attribute, docId); + for (uint32_t i = 0; i < _keys.size(); ++i) { + if (matchingKey(key, _keys[i])) { + return i; + } + } + return noKeyIdx(); + } +}; + +template +IndirectKeyHandlerT::~IndirectKeyHandlerT() +{ +} + +using IndirectIntegerKeyHandler = IndirectKeyHandlerT; +using IndirectFloatKeyHandler = IndirectKeyHandlerT; +using IndirectStringKeyHandler = IndirectKeyHandlerT; + +class ValueHandler : public AttributeNode::Handler +{ +protected: + std::unique_ptr _keyHandler; + const IAttributeVector &_attribute; + ValueHandler(std::unique_ptr keyHandler, const IAttributeVector &attribute) + : _keyHandler(std::move(keyHandler)), + _attribute(attribute) + { + } +}; + +template +class ValueHandlerT : public ValueHandler +{ + AttributeContent _values; + ResultNodeType &_result; + T _undefinedValue; +public: + ValueHandlerT(std::unique_ptr keyHandler, const IAttributeVector &attribute, ResultNodeType &result, T undefinedValue) + : ValueHandler(std::move(keyHandler), attribute), + _values(), + _result(result), + _undefinedValue(undefinedValue) + { + } + void handle(const AttributeResult & r) override { + uint32_t docId = r.getDocId(); + uint32_t keyIdx = _keyHandler->handle(docId); + if (keyIdx != AttributeMapLookupNode::KeyHandler::noKeyIdx()) { + _values.fill(_attribute, docId); + if (keyIdx < _values.size()) { + _result = _values[keyIdx]; + return; + } + } + _result = _undefinedValue; + } +}; + +template +using IntegerValueHandler = ValueHandlerT; +using FloatValueHandler = ValueHandlerT; +using StringValueHandler = ValueHandlerT; +using EnumValueHandler = ValueHandlerT; + +const IAttributeVector *findAttribute(const search::attribute::IAttributeContext &attrCtx, bool useEnumOptimization, const vespalib::string &name) +{ + const IAttributeVector *attribute = useEnumOptimization ? attrCtx.getAttributeStableEnum(name) : attrCtx.getAttribute(name); + if (attribute == nullptr) { + throw std::runtime_error(vespalib::make_string("Failed locating attribute vector '%s'", name.c_str())); + } + return attribute; +} + +IAttributeVector::largeint_t getUndefinedValue(BasicType::Type basicType) +{ + switch (basicType) { + case BasicType::INT8: + return getUndefined(); + case BasicType::INT16: + return getUndefined(); + case BasicType::INT32: + return getUndefined(); + case BasicType::INT64: + return getUndefined(); + break; + default: + return 0; + } +} + +} + +AttributeMapLookupNode::AttributeMapLookupNode() + : AttributeNode(), + _keyAttributeName(), + _valueAttributeName(), + _key(), + _keySourceAttributeName(), + _keyAttribute(nullptr), + _keySourceAttribute(nullptr) +{ +} + +AttributeMapLookupNode::AttributeMapLookupNode(const AttributeMapLookupNode &) = default; + +AttributeMapLookupNode::AttributeMapLookupNode(vespalib::stringref name) + : AttributeNode(name), + _keyAttributeName(), + _valueAttributeName(), + _key(), + _keySourceAttributeName(), + _keyAttribute(nullptr), + _keySourceAttribute(nullptr) +{ + setupAttributeNames(); +} + +AttributeMapLookupNode::~AttributeMapLookupNode() = default; + +AttributeMapLookupNode & +AttributeMapLookupNode::operator=(const AttributeMapLookupNode &rhs) = default; + +void +AttributeMapLookupNode::setupAttributeNames() +{ + vespalib::asciistream keyName; + vespalib::asciistream valueName; + auto leftBracePos = _attributeName.find('{'); + auto baseName = _attributeName.substr(0, leftBracePos); + auto rightBracePos = _attributeName.rfind('}'); + keyName << baseName << ".key"; + valueName << baseName << ".value" << _attributeName.substr(rightBracePos + 1); + _keyAttributeName = keyName.str(); + _valueAttributeName = valueName.str(); + if (rightBracePos != vespalib::string::npos && rightBracePos > leftBracePos) { + if (_attributeName[leftBracePos + 1] == '"' && _attributeName[rightBracePos - 1] == '"') { + _key = _attributeName.substr(leftBracePos + 2, rightBracePos - leftBracePos - 3); + } else if (_attributeName.substr(leftBracePos + 1, indirectKeyMarker.size()) == indirectKeyMarker && _attributeName[rightBracePos - 1] == ')') { + auto startPos = leftBracePos + 1 + indirectKeyMarker.size(); + _keySourceAttributeName = _attributeName.substr(startPos, rightBracePos - 1 - startPos); + } + } +} + +template +void +AttributeMapLookupNode::prepareIntValues(std::unique_ptr keyHandler, const IAttributeVector &attribute, IAttributeVector::largeint_t undefinedValue) +{ + auto resultNode = std::make_unique(); + _handler = std::make_unique>(std::move(keyHandler), attribute, *resultNode, undefinedValue); + setResultType(std::move(resultNode)); +} + +std::unique_ptr +AttributeMapLookupNode::makeKeyHandlerHelper() +{ + const IAttributeVector &attribute = *_keyAttribute; + if (_keySourceAttribute != nullptr) { + const IAttributeVector &keySourceAttribute = *_keySourceAttribute; + if (attribute.isIntegerType() && keySourceAttribute.isIntegerType()) { + return std::make_unique(attribute, keySourceAttribute); + } else if (attribute.isFloatingPointType() && keySourceAttribute.isFloatingPointType()) { + return std::make_unique(attribute, keySourceAttribute); + } else if (attribute.isStringType() && keySourceAttribute.isStringType()) { + return std::make_unique(attribute, keySourceAttribute); + } else { + return std::make_unique(attribute); + } + } + if (attribute.hasEnum() && _useEnumOptimization) { + return std::make_unique(attribute, _key); + } else if (attribute.isIntegerType()) { + return std::make_unique(attribute, _key); + } else if (attribute.isFloatingPointType()) { + return std::make_unique(attribute, _key); + } else if (attribute.isStringType()) { + return std::make_unique(attribute, _key); + } else { + return std::make_unique(attribute); + } +} + +std::unique_ptr +AttributeMapLookupNode::makeKeyHandler() +{ + try { + return makeKeyHandlerHelper(); + } catch (const vespalib::IllegalArgumentException &) { + return std::make_unique(*_keyAttribute); + } +} + +void +AttributeMapLookupNode::onPrepare(bool preserveAccurateTypes) +{ + auto keyHandler = makeKeyHandler(); + const IAttributeVector * attribute = _scratchResult->getAttribute(); + if (attribute != nullptr) { + BasicType::Type basicType = attribute->getBasicType(); + if (attribute->isIntegerType()) { + IAttributeVector::largeint_t undefinedValue = getUndefinedValue(basicType); + if (preserveAccurateTypes) { + switch (basicType) { + case BasicType::INT8: + prepareIntValues(std::move(keyHandler), *attribute, undefinedValue); + break; + case BasicType::INT16: + prepareIntValues(std::move(keyHandler), *attribute, undefinedValue); + break; + case BasicType::INT32: + prepareIntValues(std::move(keyHandler), *attribute, undefinedValue); + break; + case BasicType::INT64: + prepareIntValues(std::move(keyHandler), *attribute, undefinedValue); + break; + default: + throw std::runtime_error("This is no valid integer attribute " + attribute->getName()); + break; + } + } else { + prepareIntValues(std::move(keyHandler), *attribute, undefinedValue); + } + } else if (attribute->isFloatingPointType()) { + auto resultNode = std::make_unique(); + _handler = std::make_unique(std::move(keyHandler), *attribute, *resultNode, getUndefined()); + setResultType(std::move(resultNode)); + } else if (attribute->isStringType()) { + if (_useEnumOptimization) { + auto resultNode = std::make_unique(); + _handler = std::make_unique(std::move(keyHandler), *attribute, *resultNode, EnumHandle()); + setResultType(std::move(resultNode)); + } else { + auto resultNode = std::make_unique(); + _handler = std::make_unique(std::move(keyHandler), *attribute, *resultNode, ""); + setResultType(std::move(resultNode)); + } + } else { + throw std::runtime_error(vespalib::make_string("Can not deduce correct resultclass for attribute vector '%s'", + attribute->getName().c_str())); + } + } +} + +void +AttributeMapLookupNode::cleanup() +{ + _keyAttribute = nullptr; + _keySourceAttribute = nullptr; + AttributeNode::cleanup(); +} + +void +AttributeMapLookupNode::wireAttributes(const search::attribute::IAttributeContext &attrCtx) +{ + auto valueAttribute = findAttribute(attrCtx, _useEnumOptimization, _valueAttributeName); + _hasMultiValue = false; + _scratchResult = std::make_unique(valueAttribute, 0); + _keyAttribute = findAttribute(attrCtx, _useEnumOptimization, _keyAttributeName); + if (!_keySourceAttributeName.empty()) { + _keySourceAttribute = findAttribute(attrCtx, false, _keySourceAttributeName); + } +} + +void +AttributeMapLookupNode::visitMembers(vespalib::ObjectVisitor &visitor) const +{ + AttributeNode::visitMembers(visitor); + visit(visitor, "keyAttributeName", _keyAttributeName); + visit(visitor, "keySourceAttributeName", _keySourceAttributeName); + visit(visitor, "valueAttributeName", _valueAttributeName); + visit(visitor, "key", _key); +} + +} diff --git a/searchlib/src/vespa/searchlib/expression/attribute_map_lookup_node.h b/searchlib/src/vespa/searchlib/expression/attribute_map_lookup_node.h new file mode 100644 index 00000000000..36b1a718f84 --- /dev/null +++ b/searchlib/src/vespa/searchlib/expression/attribute_map_lookup_node.h @@ -0,0 +1,45 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include "attributenode.h" + +namespace search::expression { + +/** + * Extract map value from attribute for the map key specified in the + * grouping expression. + */ +class AttributeMapLookupNode : public AttributeNode +{ +public: + using IAttributeVector = search::attribute::IAttributeVector; + class KeyHandler; +private: + vespalib::string _keyAttributeName; + vespalib::string _valueAttributeName; + vespalib::string _key; + vespalib::string _keySourceAttributeName; + const IAttributeVector *_keyAttribute; + const IAttributeVector *_keySourceAttribute; + + void setupAttributeNames(); + template + void prepareIntValues(std::unique_ptr keyHandler, const IAttributeVector &attribute, IAttributeVector::largeint_t undefinedValue); + std::unique_ptr makeKeyHandlerHelper(); + std::unique_ptr makeKeyHandler(); + void cleanup() override; + void wireAttributes(const search::attribute::IAttributeContext & attrCtx) override; + void onPrepare(bool preserveAccurateTypes) override; +public: + AttributeMapLookupNode(); + AttributeMapLookupNode(vespalib::stringref name); + AttributeMapLookupNode(const AttributeMapLookupNode &); + AttributeMapLookupNode(AttributeMapLookupNode &&) = delete; + ~AttributeMapLookupNode() override; + AttributeMapLookupNode &operator=(const AttributeMapLookupNode &rhs); + AttributeMapLookupNode &operator=(AttributeMapLookupNode &&rhs) = delete; + void visitMembers(vespalib::ObjectVisitor &visitor) const override; + bool isKeyed() const override { return true; } +}; + +} -- cgit v1.2.3