diff options
author | Tor Egge <Tor.Egge@online.no> | 2024-03-06 16:06:38 +0100 |
---|---|---|
committer | Tor Egge <Tor.Egge@online.no> | 2024-03-06 16:08:10 +0100 |
commit | 0340d45620f555d5daae08016ba85663b88d165c (patch) | |
tree | 034ab941bc0eea0da41ec3d40a1e2a3786c99aba /searchlib | |
parent | 296c4a2be1e8a0d521c036eb30a709364ceacc57 (diff) |
Add interpolated lookup for streaming search.
Diffstat (limited to 'searchlib')
11 files changed, 236 insertions, 1 deletions
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/expression/ForceLoad.java b/searchlib/src/main/java/com/yahoo/searchlib/expression/ForceLoad.java index 840fb43cfa0..c5fd6e5c68f 100644 --- a/searchlib/src/main/java/com/yahoo/searchlib/expression/ForceLoad.java +++ b/searchlib/src/main/java/com/yahoo/searchlib/expression/ForceLoad.java @@ -46,6 +46,7 @@ public class ForceLoad { "ExpressionNode", "AggregationRefNode", "IntegerResultNode", + "InterpolatedDocumentFieldLookupNode", "Int32ResultNode", "Int16ResultNode", "Int8ResultNode", diff --git a/searchlib/src/main/java/com/yahoo/searchlib/expression/InterpolatedDocumentFieldLookupNode.java b/searchlib/src/main/java/com/yahoo/searchlib/expression/InterpolatedDocumentFieldLookupNode.java new file mode 100644 index 00000000000..15605eb4d68 --- /dev/null +++ b/searchlib/src/main/java/com/yahoo/searchlib/expression/InterpolatedDocumentFieldLookupNode.java @@ -0,0 +1,42 @@ +package com.yahoo.searchlib.expression; + +import com.yahoo.vespa.objects.ObjectVisitor; + +/* + * Streaming search version of InterpolatedLookupNode. + */ +public class InterpolatedDocumentFieldLookupNode extends InterpolatedLookupNode { + public static final int classId = registerClass(0x4000 + 166, InterpolatedDocumentFieldLookupNode.class, InterpolatedDocumentFieldLookupNode::new); + + /** + * Constructs an empty result node. + * <b>NOTE:</b> This instance is broken until non-optional member data is set. + */ + public InterpolatedDocumentFieldLookupNode() { + super(); + } + + /** + * Constructs an instance of this class with given field name + * and lookup argument. + * + * @param field The field to retrieve. + * @param arg Expression evaluating to the lookup argument. + */ + public InterpolatedDocumentFieldLookupNode(String field, ExpressionNode arg) { + super(field, arg); + } + + @Override + protected int onGetClassId() { + return classId; + } + + public String getFieldName() { return super.getAttributeName(); } + + @Override + public void visitMembers(ObjectVisitor visitor) { + super.visitSuperMembers(visitor); + visitor.visit("field", getFieldName()); + } +} diff --git a/searchlib/src/main/java/com/yahoo/searchlib/expression/InterpolatedLookupNode.java b/searchlib/src/main/java/com/yahoo/searchlib/expression/InterpolatedLookupNode.java index e8ebfad0b0d..73626a8f5f0 100644 --- a/searchlib/src/main/java/com/yahoo/searchlib/expression/InterpolatedLookupNode.java +++ b/searchlib/src/main/java/com/yahoo/searchlib/expression/InterpolatedLookupNode.java @@ -91,4 +91,8 @@ public class InterpolatedLookupNode extends UnaryFunctionNode { visitor.visit("attribute", attribute); } + protected void visitSuperMembers(ObjectVisitor visitor) { + super.visitMembers(visitor); + } + } diff --git a/searchlib/src/vespa/searchlib/aggregation/modifiers.cpp b/searchlib/src/vespa/searchlib/aggregation/modifiers.cpp index d2a27b7bedd..81664ce66eb 100644 --- a/searchlib/src/vespa/searchlib/aggregation/modifiers.cpp +++ b/searchlib/src/vespa/searchlib/aggregation/modifiers.cpp @@ -6,6 +6,8 @@ #include <vespa/searchlib/expression/attributenode.h> #include <vespa/searchlib/expression/attribute_map_lookup_node.h> #include <vespa/searchlib/expression/documentfieldnode.h> +#include <vespa/searchlib/expression/interpolated_document_field_lookup_node.h> +#include <vespa/searchlib/expression/interpolatedlookupfunctionnode.h> using namespace search::expression; @@ -63,6 +65,10 @@ AttributeNodeReplacer::execute(vespalib::Identifiable &obj) std::unique_ptr<ExpressionNode> Attribute2DocumentAccessor::getReplacementNode(const AttributeNode &attributeNode) { + if (attributeNode.inherits(InterpolatedLookup::classId)) { + auto& interpolated_lookup = static_cast<const InterpolatedLookup&>(attributeNode); + return std::make_unique<InterpolatedDocumentFieldLookupNode>(interpolated_lookup.getAttributeName(), interpolated_lookup.clone_lookup_expression()); + } return std::make_unique<DocumentFieldNode>(attributeNode.getAttributeName()); } diff --git a/searchlib/src/vespa/searchlib/common/identifiable.h b/searchlib/src/vespa/searchlib/common/identifiable.h index 4576f24f065..b80e1d5de2f 100644 --- a/searchlib/src/vespa/searchlib/common/identifiable.h +++ b/searchlib/src/vespa/searchlib/common/identifiable.h @@ -172,5 +172,7 @@ #define CID_TensorAttribute SEARCHLIB_CID(164) #define CID_ReferenceAttribute SEARCHLIB_CID(165) +#define CID_search_expression_InterpolatedDocumentFieldLookupNode SEARCHLIB_CID(166) + #define CID_search_NormalSketch SEARCHLIB_CID(170) #define CID_search_SparseSketch SEARCHLIB_CID(171) diff --git a/searchlib/src/vespa/searchlib/expression/CMakeLists.txt b/searchlib/src/vespa/searchlib/expression/CMakeLists.txt index 11c0b478e23..5c6039a1b5f 100644 --- a/searchlib/src/vespa/searchlib/expression/CMakeLists.txt +++ b/searchlib/src/vespa/searchlib/expression/CMakeLists.txt @@ -25,6 +25,7 @@ vespa_add_library(searchlib_expression OBJECT mathfunctionnode.cpp numericfunctionnode.cpp resultnode.cpp + interpolated_document_field_lookup_node.cpp interpolatedlookupfunctionnode.cpp functionnodes.cpp resultnodes.cpp diff --git a/searchlib/src/vespa/searchlib/expression/documentfieldnode.h b/searchlib/src/vespa/searchlib/expression/documentfieldnode.h index 1362234d4a4..915f6de5c6c 100644 --- a/searchlib/src/vespa/searchlib/expression/documentfieldnode.h +++ b/searchlib/src/vespa/searchlib/expression/documentfieldnode.h @@ -40,7 +40,7 @@ public: DocumentFieldNode(DocumentFieldNode && rhs) noexcept = default; DocumentFieldNode & operator = (DocumentFieldNode && rhs) noexcept = default; const vespalib::string & getFieldName() const override { return _fieldName; } -private: +public: class Handler : public document::fieldvalue::IteratorHandler { public: virtual void reset() = 0; @@ -48,6 +48,7 @@ private: void onCollectionStart(const Content & c) override; void onStructStart(const Content & c) override; }; +private: class SingleHandler : public Handler { public: SingleHandler(ResultNode & result) : _result(result) {} @@ -71,6 +72,7 @@ private: bool onExecute() const override; void onDoc(const document::Document & doc) override; void onDocType(const document::DocumentType & docType) override; +protected: document::FieldPath _fieldPath; mutable ResultNode::CP _value; mutable std::unique_ptr<Handler> _handler; diff --git a/searchlib/src/vespa/searchlib/expression/interpolated_document_field_lookup_node.cpp b/searchlib/src/vespa/searchlib/expression/interpolated_document_field_lookup_node.cpp new file mode 100644 index 00000000000..a00465c9144 --- /dev/null +++ b/searchlib/src/vespa/searchlib/expression/interpolated_document_field_lookup_node.cpp @@ -0,0 +1,133 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "interpolated_document_field_lookup_node.h" +#include "simple_interpolate.h" +#include <vespa/document/fieldvalue/document.h> + +using vespalib::Serializer; +using vespalib::Deserializer; + +namespace search::expression { + +namespace { + +class InterpolateHandler : public InterpolatedDocumentFieldLookupNode::Handler { + std::vector<double>& _values; +public: + InterpolateHandler(std::vector<double>& values); + ~InterpolateHandler() override; + void reset() override; + void onPrimitive(uint32_t fid, const Content& c) override; +}; + +InterpolateHandler::InterpolateHandler(std::vector<double>& values) + : InterpolatedDocumentFieldLookupNode::Handler(), + _values(values) +{ +} + +InterpolateHandler::~InterpolateHandler() = default; + +void +InterpolateHandler::reset() +{ +} + +void +InterpolateHandler::onPrimitive(uint32_t, const Content& c) +{ + _values.push_back(c.getValue().getAsDouble()); +} + +} + +IMPLEMENT_EXPRESSIONNODE(InterpolatedDocumentFieldLookupNode, DocumentFieldNode); + +InterpolatedDocumentFieldLookupNode::InterpolatedDocumentFieldLookupNode() noexcept + : DocumentFieldNode(), + _lookup_expression(), + _values(), + _float_result() +{ +} + +InterpolatedDocumentFieldLookupNode::InterpolatedDocumentFieldLookupNode(vespalib::stringref name, std::unique_ptr<ExpressionNode> arg) + : DocumentFieldNode(name), + _lookup_expression(std::move(arg)), + _values(), + _float_result() +{ +} + +InterpolatedDocumentFieldLookupNode::InterpolatedDocumentFieldLookupNode(const InterpolatedDocumentFieldLookupNode &rhs) = default; + +InterpolatedDocumentFieldLookupNode::~InterpolatedDocumentFieldLookupNode() = default; + +InterpolatedDocumentFieldLookupNode& +InterpolatedDocumentFieldLookupNode::operator=(const InterpolatedDocumentFieldLookupNode &rhs) = default; + +Serializer & +InterpolatedDocumentFieldLookupNode::onSerialize(Serializer & os) const +{ + os << _value; + os << uint32_t(1) << _lookup_expression; + os << _fieldName; + return os; +} + +Deserializer & +InterpolatedDocumentFieldLookupNode::onDeserialize(Deserializer & is) +{ + is >> _value; + uint32_t count(0); + is >> count; + if (count > 0) { + is >> _lookup_expression; + } else { + _lookup_expression.reset(); + } + is >> _fieldName; + return is; +} + +void +InterpolatedDocumentFieldLookupNode::visitMembers(vespalib::ObjectVisitor & visitor) const +{ + DocumentFieldNode::visitMembers(visitor); + visit(visitor, "index", *_lookup_expression); +} + +void +InterpolatedDocumentFieldLookupNode::selectMembers(const vespalib::ObjectPredicate & predicate, vespalib::ObjectOperation & operation) +{ + DocumentFieldNode::selectMembers(predicate, operation); + if (_lookup_expression) { + _lookup_expression->select(predicate, operation); + } +} + +void +InterpolatedDocumentFieldLookupNode::onPrepare(bool) +{ + _handler = std::make_unique<InterpolateHandler>(_values); + _value = std::make_unique<FloatResultNode>(); +} + +bool +InterpolatedDocumentFieldLookupNode::onExecute() const +{ + if (_lookup_expression) { + _values.clear(); + _doc->iterateNested(_fieldPath.getFullRange(), *_handler); + _lookup_expression->execute(); + auto lookup = _lookup_expression->getResult()->getFloat(); + auto result = simple_interpolate(_values, lookup); + _float_result.set(result); + } else { + _float_result.set(0.0); + } + _value->set(_float_result); + return true; +} + +} diff --git a/searchlib/src/vespa/searchlib/expression/interpolated_document_field_lookup_node.h b/searchlib/src/vespa/searchlib/expression/interpolated_document_field_lookup_node.h new file mode 100644 index 00000000000..69f0849cf20 --- /dev/null +++ b/searchlib/src/vespa/searchlib/expression/interpolated_document_field_lookup_node.h @@ -0,0 +1,33 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#pragma once + +#include "documentfieldnode.h" + +namespace search::expression { + +/* + * Interpolated lookup for streaming search. + */ +class InterpolatedDocumentFieldLookupNode : public DocumentFieldNode +{ +public: + DECLARE_EXPRESSIONNODE(InterpolatedDocumentFieldLookupNode); + DECLARE_NBO_SERIALIZE; + + InterpolatedDocumentFieldLookupNode() noexcept; + InterpolatedDocumentFieldLookupNode(vespalib::stringref name, std::unique_ptr<ExpressionNode> arg); + InterpolatedDocumentFieldLookupNode(const InterpolatedDocumentFieldLookupNode& rhs); + ~InterpolatedDocumentFieldLookupNode() override; + InterpolatedDocumentFieldLookupNode& operator=(const InterpolatedDocumentFieldLookupNode &rhs); + void visitMembers(vespalib::ObjectVisitor& visitor) const override; + void selectMembers(const vespalib::ObjectPredicate& predicate, vespalib::ObjectOperation& operation) override; +private: + void onPrepare(bool preserveAccurateTypes) override; + bool onExecute() const override; + vespalib::IdentifiablePtr<ExpressionNode> _lookup_expression; + mutable std::vector<double> _values; + mutable FloatResultNode _float_result; +}; + +} diff --git a/searchlib/src/vespa/searchlib/expression/interpolatedlookupfunctionnode.cpp b/searchlib/src/vespa/searchlib/expression/interpolatedlookupfunctionnode.cpp index fbc69a512d3..45f4f8e5fb1 100644 --- a/searchlib/src/vespa/searchlib/expression/interpolatedlookupfunctionnode.cpp +++ b/searchlib/src/vespa/searchlib/expression/interpolatedlookupfunctionnode.cpp @@ -116,4 +116,14 @@ InterpolatedLookup::selectMembers(const vespalib::ObjectPredicate & predicate, v } } +std::unique_ptr<ExpressionNode> +InterpolatedLookup::clone_lookup_expression() const +{ + if (_lookupExpression) { + return std::unique_ptr<ExpressionNode>(_lookupExpression->clone()); + } else { + return {}; + } +} + } diff --git a/searchlib/src/vespa/searchlib/expression/interpolatedlookupfunctionnode.h b/searchlib/src/vespa/searchlib/expression/interpolatedlookupfunctionnode.h index 8eb05d1f0d1..57b699c821d 100644 --- a/searchlib/src/vespa/searchlib/expression/interpolatedlookupfunctionnode.h +++ b/searchlib/src/vespa/searchlib/expression/interpolatedlookupfunctionnode.h @@ -21,6 +21,7 @@ public: InterpolatedLookup & operator= (const InterpolatedLookup &rhs); void visitMembers(vespalib::ObjectVisitor & visitor) const override; void selectMembers(const vespalib::ObjectPredicate & predicate, vespalib::ObjectOperation & operation) override; + std::unique_ptr<ExpressionNode> clone_lookup_expression() const; private: std::pair<std::unique_ptr<ResultNode>, std::unique_ptr<Handler>> createResultHandler(bool preserveAccurateType, const attribute::IAttributeVector & attribute) const override; |