diff options
15 files changed, 149 insertions, 67 deletions
diff --git a/searchcore/src/tests/proton/docsummary/docsummary.cpp b/searchcore/src/tests/proton/docsummary/docsummary.cpp index a0b947e11f8..d0705e7b538 100644 --- a/searchcore/src/tests/proton/docsummary/docsummary.cpp +++ b/searchcore/src/tests/proton/docsummary/docsummary.cpp @@ -26,6 +26,8 @@ #include <vespa/searchcore/proton/common/hw_info.h> #include <vespa/vespalib/data/slime/slime.h> #include <vespa/config/helper/configgetter.hpp> +#include <vespa/vespalib/tensor/serialization/typed_binary_format.h> +#include <vespa/vespalib/objects/nbostream.h> #include <vespa/log/log.h> LOG_SETUP("docsummary_test"); @@ -300,10 +302,18 @@ private: uint32_t id, uint32_t resultClassID); + void + assertTensor(const Tensor::UP &exp, + const std::string &fieldName, + const DocsumReply &reply, + uint32_t id, + uint32_t resultClassID); + bool assertSlime(const std::string &exp, const DocsumReply &reply, - uint32_t id); + uint32_t id, + bool relaxed = false); void requireThatAdapterHandlesAllFieldTypes(); @@ -400,8 +410,26 @@ Test::assertString(const std::string & exp, const std::string & fieldName, } +void +Test::assertTensor(const Tensor::UP & exp, const std::string & fieldName, + const DocsumReply & reply, + uint32_t id, uint32_t resultClassID) +{ + GeneralResultPtr res = getResult(reply, id, resultClassID); + const void *data = res->GetEntry(fieldName.c_str())->_stringval; + size_t len = res->GetEntry(fieldName.c_str())->_stringlen; + EXPECT_EQUAL(exp.get() == nullptr, len == 0u); + if (exp) { + vespalib::nbostream serialized(data, len); + Tensor::UP tensor = vespalib::tensor::TypedBinaryFormat::deserialize(serialized); + EXPECT_TRUE(tensor.get() != nullptr); + EXPECT_EQUAL(*exp, *tensor); + } +} + + bool -Test::assertSlime(const std::string &exp, const DocsumReply &reply, uint32_t id) +Test::assertSlime(const std::string &exp, const DocsumReply &reply, uint32_t id, bool relaxed) { const DocsumReply::Docsum & docsum = reply.docsums[id]; uint32_t classId; @@ -414,6 +442,14 @@ Test::assertSlime(const std::string &exp, const DocsumReply &reply, uint32_t id) size_t decodeRes = vespalib::slime::BinaryFormat::decode(serialized, slime); ASSERT_EQUAL(decodeRes, serialized.size); + if (relaxed) { + vespalib::slime::SimpleBuffer buf; + vespalib::slime::JsonFormat::encode(slime, buf, false); + vespalib::Slime tmpSlime; + size_t used = vespalib::slime::JsonFormat::decode(buf.get(), tmpSlime); + EXPECT_EQUAL(buf.get().size, used); + slime = std::move(tmpSlime); + } vespalib::Slime expSlime; size_t used = vespalib::slime::JsonFormat::decode(exp, expSlime); EXPECT_EQUAL(exp.size(), used); @@ -726,7 +762,7 @@ Test::requireThatAttributesAreUsed() endElement(). endField(). startAttributeField("bj"). - addTensor(createTensor({ {{}, 3} }, { "x", "y"})). + addTensor(createTensor({ {{{"x","f"},{"y","g"}}, 3} }, { "x", "y"})). endField(). endDocument(), 2); @@ -755,9 +791,8 @@ Test::requireThatAttributesAreUsed() *rep, 0, rclass)); EXPECT_TRUE(assertString("[[\"quux\",7],[\"qux\",6]]", "bi", *rep, 0, rclass)); - EXPECT_TRUE(assertString("{\"dimensions\":[\"x\",\"y\"]," - "\"cells\":[{\"address\":{},\"value\":3}]}", - "bj", *rep, 0, rclass)); + TEST_DO(assertTensor(createTensor({ {{{"x","f"},{"y","g"}}, 3} }, { "x", "y"}), + "bj", *rep, 0, rclass)); // empty doc EXPECT_TRUE(search::attribute::isUndefined<int32_t> @@ -771,7 +806,7 @@ Test::requireThatAttributesAreUsed() EXPECT_TRUE(assertString("[]", "bg", *rep, 1, rclass)); EXPECT_TRUE(assertString("[]", "bh", *rep, 1, rclass)); EXPECT_TRUE(assertString("[]", "bi", *rep, 1, rclass)); - EXPECT_TRUE(assertString("", "bj", *rep, 1, rclass)); + TEST_DO(assertTensor(Tensor::UP(), "bj", *rep, 1, rclass)); proton::IAttributeManager::SP attributeManager = dc._ddb->getReadySubDB()->getAttributeManager(); @@ -785,14 +820,13 @@ Test::requireThatAttributesAreUsed() attributeFieldWriter. execute("bj", [&]() { bjTensorAttr->setTensor(3, - *createTensor({ {{}, 4} }, { "x"})); + *createTensor({ {{{"x", "a"},{"y", "b"}}, 4} }, { "x"})); bjTensorAttr->commit(); }); attributeFieldWriter.sync(); DocsumReply::UP rep2 = dc._ddb->getDocsums(req); - EXPECT_TRUE(assertString("{\"dimensions\":[\"x\",\"y\"]," - "\"cells\":[{\"address\":{},\"value\":4}]}", - "bj", *rep2, 1, rclass)); + TEST_DO(assertTensor(createTensor({ {{{"x","a"},{"y","b"}}, 4} }, { "x", "y"}), + "bj", *rep2, 1, rclass)); DocsumRequest req3; req3.resultClassName = "class3"; @@ -802,9 +836,8 @@ Test::requireThatAttributesAreUsed() EXPECT_TRUE(assertSlime("{bd:[],be:[],bf:[],bg:[]," "bh:[],bi:[]," - "bj:{dimensions:['x','y']," - "cells:[{address:{},value:4.0}]}}", - *rep3, 0)); + "bj:'0x01020178017901016101624010000000000000'}", + *rep3, 0, true)); } diff --git a/searchcore/src/tests/proton/docsummary/summary.cfg b/searchcore/src/tests/proton/docsummary/summary.cfg index 52f300ae3e0..33fd90f4c82 100644 --- a/searchcore/src/tests/proton/docsummary/summary.cfg +++ b/searchcore/src/tests/proton/docsummary/summary.cfg @@ -85,7 +85,7 @@ classes[3].fields[7].type "jsonstring" classes[3].fields[8].name "bi" classes[3].fields[8].type "jsonstring" classes[3].fields[9].name "bj" -classes[3].fields[9].type "jsonstring" +classes[3].fields[9].type "tensor" classes[4].name "class4" classes[4].id 4 classes[4].fields[1] diff --git a/searchcore/src/tests/proton/docsummary/summaryfieldconverter_test.cpp b/searchcore/src/tests/proton/docsummary/summaryfieldconverter_test.cpp index e9496093cfe..27a50c9c57f 100644 --- a/searchcore/src/tests/proton/docsummary/summaryfieldconverter_test.cpp +++ b/searchcore/src/tests/proton/docsummary/summaryfieldconverter_test.cpp @@ -150,6 +150,7 @@ class Test : public vespalib::TestApp { void checkString(const string &str, const FieldValue *value); void checkData(const search::RawBuf &data, const FieldValue *value); + void checkTensor(const Tensor::UP &tensor, const FieldValue *value); template <unsigned int N> void checkArray(const char *(&str)[N], const FieldValue *value); void setSummaryField(const string &name); @@ -170,7 +171,7 @@ class Test : public vespalib::TestApp { void requireThatSearchDataTypeUsesDefaultDataTypes(); void requireThatLinguisticsAnnotationUsesDefaultDataTypes(); void requireThatPredicateIsPrinted(); - void requireThatTensorIsPrinted(); + void requireThatTensorIsNotConverted(); const DocumentType &getDocType() const { return *_documentType; } Document makeDocument(); StringFieldValue annotateTerm(const string &term); @@ -245,7 +246,7 @@ Test::Main() TEST_CALL(requireThatSearchDataTypeUsesDefaultDataTypes()); TEST_CALL(requireThatLinguisticsAnnotationUsesDefaultDataTypes()); TEST_CALL(requireThatPredicateIsPrinted()); - TEST_CALL(requireThatTensorIsPrinted()); + TEST_CALL(requireThatTensorIsNotConverted()); TEST_DONE(); } @@ -430,6 +431,17 @@ void Test::checkData(const search::RawBuf &buf, const FieldValue *value) { EXPECT_TRUE(memcmp(buf.GetDrainPos(), got.first, got.second) == 0); } +void Test::checkTensor(const Tensor::UP &tensor, const FieldValue *value) { + ASSERT_TRUE(value); + const TensorFieldValue *s = dynamic_cast<const TensorFieldValue *>(value); + ASSERT_TRUE(s); + const Tensor::UP &tvalue = s->getAsTensorPtr(); + EXPECT_EQUAL(tensor.get() != nullptr, tvalue.get() != nullptr); + if (tensor) { + EXPECT_EQUAL(*tensor, *tvalue); + } +} + template <unsigned int N> void Test::checkArray(const char *(&str)[N], const FieldValue *value) { ASSERT_TRUE(value); @@ -649,7 +661,7 @@ createTensor(const TensorCells &cells, const TensorDimensions &dimensions) { } void -Test::requireThatTensorIsPrinted() +Test::requireThatTensorIsNotConverted() { TensorFieldValue tensorFieldValue; tensorFieldValue = createTensor({ {{{"x", "4"}, {"y", "5"}}, 7} }, @@ -658,30 +670,17 @@ Test::requireThatTensorIsPrinted() doc.setRepo(*_documentRepo); doc.setValue("tensor", tensorFieldValue); - FieldBlock expect1("{ dimensions: [ 'x', 'y' ], cells: [" - "{ address: { x:'4', y:'5' }, value: 7.0 }" - "] }"); - - TEST_CALL(checkString(expect1.json, + TEST_CALL(checkTensor(createTensor({ {{{"x", "4"}, {"y", "5"}}, 7} }, + {"x", "y"}), SFC::convertSummaryField(false, *doc.getValue("tensor"), - false).get())); - TEST_CALL(checkData(expect1.binary, - SFC::convertSummaryField(false, - *doc.getValue("tensor"), - true).get())); + true).get())); doc.setValue("tensor", TensorFieldValue()); - FieldBlock expect2("{ }"); - - TEST_CALL(checkString(expect2.json, + TEST_CALL(checkTensor(Tensor::UP(), SFC::convertSummaryField(false, *doc.getValue("tensor"), - false).get())); - TEST_CALL(checkData(expect2.binary, - SFC::convertSummaryField(false, - *doc.getValue("tensor"), - true).get())); + true).get())); } } // namespace diff --git a/searchcore/src/vespa/searchcore/proton/docsummary/documentstoreadapter.cpp b/searchcore/src/vespa/searchcore/proton/docsummary/documentstoreadapter.cpp index 855126bd064..4f61873b938 100644 --- a/searchcore/src/vespa/searchcore/proton/docsummary/documentstoreadapter.cpp +++ b/searchcore/src/vespa/searchcore/proton/docsummary/documentstoreadapter.cpp @@ -3,11 +3,16 @@ #include "documentstoreadapter.h" #include "summaryfieldconverter.h" #include <vespa/document/fieldvalue/stringfieldvalue.h> +#include <vespa/vespalib/tensor/tensor.h> +#include <vespa/vespalib/tensor/serialization/typed_binary_format.h> +#include <vespa/vespalib/objects/nbostream.h> +#include <vespa/document/fieldvalue/tensorfieldvalue.h> #include <vespa/log/log.h> LOG_SETUP(".proton.docsummary.documentstoreadapter"); using namespace document; using namespace search::docsummary; +using vespalib::tensor::Tensor; namespace proton { @@ -76,6 +81,18 @@ DocumentStoreAdapter::writeField(const FieldValue &value, ResType type) std::pair<const char *, size_t> buf = value.getAsRaw(); return _resultPacker.AddLongData(buf.first, buf.second); } + case RES_TENSOR: + { + vespalib::nbostream serialized; + if (value.getClass().inherits(TensorFieldValue::classId)) { + const TensorFieldValue &tvalue = static_cast<const TensorFieldValue &>(value); + const std::unique_ptr<Tensor> &tensor = tvalue.getAsTensorPtr(); + if (tensor) { + vespalib::tensor::TypedBinaryFormat::serialize(serialized, *tensor); + } + } + return _resultPacker.AddSerializedTensor(serialized.peek(), serialized.size()); + } default: LOG(warning, "Unknown docsum field type: %s. Add empty field", diff --git a/searchcore/src/vespa/searchcore/proton/docsummary/summaryfieldconverter.cpp b/searchcore/src/vespa/searchcore/proton/docsummary/summaryfieldconverter.cpp index 0c4d739be79..c74442bd72b 100644 --- a/searchcore/src/vespa/searchcore/proton/docsummary/summaryfieldconverter.cpp +++ b/searchcore/src/vespa/searchcore/proton/docsummary/summaryfieldconverter.cpp @@ -42,6 +42,8 @@ #include <vespa/vespalib/data/slime/binary_format.h> #include <vespa/vespalib/data/slime/json_format.h> #include <vespa/vespalib/tensor/serialization/slime_binary_format.h> +#include <vespa/vespalib/tensor/serialization/typed_binary_format.h> +#include <vespa/vespalib/objects/nbostream.h> #include <vespa/searchlib/util/slime_output_raw_buf_adapter.h> #include <vespa/vespalib/util/exceptions.h> @@ -472,7 +474,7 @@ class SummaryFieldValueConverter : protected ConstFieldValueVisitor } virtual void visit(const TensorFieldValue &value) override { - _field_value = _structuredFieldConverter.convert(value); + visitPrimitive(value); } public: @@ -632,12 +634,11 @@ class SlimeFiller : public ConstFieldValueVisitor { virtual void visit(const TensorFieldValue &value) override { const auto &tensor = value.getAsTensorPtr(); + vespalib::nbostream s; if (tensor) { - vespalib::tensor::SlimeBinaryFormat::serialize(_inserter, *tensor); - } else { - // No tensor value => empty object - _inserter.insertObject(); + vespalib::tensor::TypedBinaryFormat::serialize(s, *tensor); } + _inserter.insertData(vespalib::slime::Memory(s.peek(), s.size())); } public: diff --git a/searchsummary/src/vespa/searchsummary/docsummary/attributedfw.cpp b/searchsummary/src/vespa/searchsummary/docsummary/attributedfw.cpp index b0704b2d148..cb8a3dc7680 100644 --- a/searchsummary/src/vespa/searchsummary/docsummary/attributedfw.cpp +++ b/searchsummary/src/vespa/searchsummary/docsummary/attributedfw.cpp @@ -8,7 +8,8 @@ #include "attributedfw.h" #include "docsumstate.h" #include <vespa/vespalib/tensor/tensor.h> -#include <vespa/vespalib/tensor/serialization/slime_binary_format.h> +#include <vespa/vespalib/tensor/serialization/typed_binary_format.h> +#include <vespa/vespalib/objects/nbostream.h> #include <vespa/vespalib/data/slime/slime.h> #include <vespa/log/log.h> @@ -44,7 +45,13 @@ ResType inferType(const IAttributeVector & vec) { } else if (vec.isFloatingPointType()) { retval = (fw == sizeof(float)) ? RES_FLOAT : RES_DOUBLE; } else { - retval = RES_STRING; + BasicType::Type t = vec.getBasicType(); + switch (t) { + case BasicType::TENSOR: + retval = RES_TENSOR; + default: + retval = RES_STRING; + } } } } @@ -133,34 +140,27 @@ SingleAttrDFW::WriteField(uint32_t docid, target->append(s, slen); return (sizeof(slen) + slen); break; } - case RES_JSONSTRING: { + case RES_TENSOR: { + vespalib::nbostream str; BasicType::Type t = v.getBasicType(); switch (t) { case BasicType::TENSOR: { const tensor::TensorAttribute &tv = static_cast<const tensor::TensorAttribute &>(v); const auto tensor = tv.getTensor(docid); - vespalib::string str; if (tensor) { - auto slime = - vespalib::tensor::SlimeBinaryFormat::serialize(*tensor); - vespalib::slime::SimpleBuffer buf; - vespalib::slime::JsonFormat::encode(*slime, buf, true); - str = buf.get().make_string(); - } else { - // No tensor value => empty object - str = ""; + vespalib::tensor::TypedBinaryFormat::serialize(str, *tensor); } - uint32_t slen = str.size(); - target->append(&slen, sizeof(slen)); - target->append(str.c_str(), slen); - return (sizeof(slen) + slen); } default: break; - }; + } + uint32_t slen = str.size(); + target->append(&slen, sizeof(slen)); + target->append(str.peek(), slen); + return (sizeof(slen) + slen); } - /* FALLTHROUGH */ + case RES_JSONSTRING: case RES_XMLSTRING: case RES_FEATUREDATA: case RES_LONG_STRING: @@ -222,7 +222,7 @@ SingleAttrDFW::insertField(uint32_t docid, target.insertLong(val); break; } - case RES_JSONSTRING: { + case RES_TENSOR: { BasicType::Type t = v.getBasicType(); switch (t) { case BasicType::TENSOR: { @@ -230,17 +230,17 @@ SingleAttrDFW::insertField(uint32_t docid, static_cast<const tensor::TensorAttribute &>(v); const auto tensor = tv.getTensor(docid); if (tensor) { - vespalib::tensor::SlimeBinaryFormat::serialize(target, *tensor); - } else { - // No tensor value => no object + vespalib::nbostream str; + vespalib::tensor::TypedBinaryFormat::serialize(str, *tensor); + target.insertData(vespalib::slime::Memory(str.peek(), str.size())); } - return; } default: - break; - }; + ; + } } - /* FALLTHROUGH */ + break; + case RES_JSONSTRING: case RES_XMLSTRING: case RES_FEATUREDATA: case RES_LONG_STRING: diff --git a/searchsummary/src/vespa/searchsummary/docsummary/docsumfieldwriter.cpp b/searchsummary/src/vespa/searchsummary/docsummary/docsumfieldwriter.cpp index be188e9a871..446ca347bff 100644 --- a/searchsummary/src/vespa/searchsummary/docsummary/docsumfieldwriter.cpp +++ b/searchsummary/src/vespa/searchsummary/docsummary/docsumfieldwriter.cpp @@ -164,6 +164,7 @@ CopyDFW::insertField(uint32_t /*docid*/, target.insertString(value); break; } + case RES_TENSOR: case RES_LONG_DATA: case RES_DATA: { uint32_t len; @@ -259,6 +260,7 @@ CopyDFW::WriteField(uint32_t docid, break; } + case RES_TENSOR: case RES_LONG_DATA: { uint32_t flen = entry->_len; diff --git a/searchsummary/src/vespa/searchsummary/docsummary/docsumformat.cpp b/searchsummary/src/vespa/searchsummary/docsummary/docsumformat.cpp index a837fca3bdb..27b20f8b1bd 100644 --- a/searchsummary/src/vespa/searchsummary/docsummary/docsumformat.cpp +++ b/searchsummary/src/vespa/searchsummary/docsummary/docsumformat.cpp @@ -97,6 +97,7 @@ DocsumFormat::addEmpty(ResType type, search::RawBuf &target) case RES_LONG_DATA: case RES_XMLSTRING: case RES_JSONSTRING: + case RES_TENSOR: case RES_FEATUREDATA: return addLongData(target, "", 0); } diff --git a/searchsummary/src/vespa/searchsummary/docsummary/docsumwriter.cpp b/searchsummary/src/vespa/searchsummary/docsummary/docsumwriter.cpp index f790d38e70e..4273c89d7f5 100644 --- a/searchsummary/src/vespa/searchsummary/docsummary/docsumwriter.cpp +++ b/searchsummary/src/vespa/searchsummary/docsummary/docsumwriter.cpp @@ -151,6 +151,7 @@ DynamicDocsumWriter::RepackDocsum(GeneralResult *gres, written += slen; break; } + case RES_TENSOR: case RES_LONG_DATA: { uint32_t flen = entry->_len; uint32_t dlen = entry->_get_length(); @@ -304,6 +305,7 @@ static void convertEntry(GetDocsumsState *state, inserter.insertString(Memory(ptr, len)); break; case RES_DATA: + case RES_TENSOR: case RES_LONG_DATA: entry->_resolve_field(&ptr, &len, &state->_docSumFieldSpace); inserter.insertData(Memory(ptr, len)); diff --git a/searchsummary/src/vespa/searchsummary/docsummary/resultclass.h b/searchsummary/src/vespa/searchsummary/docsummary/resultclass.h index e35408a796c..58a245a364a 100644 --- a/searchsummary/src/vespa/searchsummary/docsummary/resultclass.h +++ b/searchsummary/src/vespa/searchsummary/docsummary/resultclass.h @@ -31,6 +31,7 @@ enum ResType { RES_LONG_DATA, RES_XMLSTRING, RES_JSONSTRING, + RES_TENSOR, RES_FEATUREDATA }; diff --git a/searchsummary/src/vespa/searchsummary/docsummary/resultconfig.cpp b/searchsummary/src/vespa/searchsummary/docsummary/resultconfig.cpp index a08b0d11d5e..aa3029b9535 100644 --- a/searchsummary/src/vespa/searchsummary/docsummary/resultconfig.cpp +++ b/searchsummary/src/vespa/searchsummary/docsummary/resultconfig.cpp @@ -55,6 +55,7 @@ ResultConfig::GetResTypeName(ResType type) case RES_LONG_DATA: return "longdata"; case RES_XMLSTRING: return "xmlstring"; case RES_JSONSTRING: return "jsonstring"; + case RES_TENSOR: return "tensor"; case RES_FEATUREDATA: return "featuredata"; } return "unknown-type"; @@ -172,6 +173,8 @@ ResultConfig::ReadConfig(const vespa::config::search::SummaryConfig &cfg, const rc = resClass->AddConfigEntry(fieldname, RES_XMLSTRING); } else if (strcmp(fieldtype, "jsonstring") == 0) { rc = resClass->AddConfigEntry(fieldname, RES_JSONSTRING); + } else if (strcmp(fieldtype, "tensor") == 0) { + rc = resClass->AddConfigEntry(fieldname, RES_TENSOR); } else if (strcmp(fieldtype, "featuredata") == 0) { rc = resClass->AddConfigEntry(fieldname, RES_FEATUREDATA); } else { // FAIL: unknown field type diff --git a/searchsummary/src/vespa/searchsummary/docsummary/resultconfig.h b/searchsummary/src/vespa/searchsummary/docsummary/resultconfig.h index 7082a5636cc..4ae1b14e486 100644 --- a/searchsummary/src/vespa/searchsummary/docsummary/resultconfig.h +++ b/searchsummary/src/vespa/searchsummary/docsummary/resultconfig.h @@ -164,6 +164,8 @@ public: case RES_DATA: case RES_LONG_DATA: return (b == RES_DATA || b == RES_LONG_DATA); + case RES_TENSOR: + return (b == RES_TENSOR); case RES_FEATUREDATA: return (b == RES_FEATUREDATA); } diff --git a/searchsummary/src/vespa/searchsummary/docsummary/resultpacker.cpp b/searchsummary/src/vespa/searchsummary/docsummary/resultpacker.cpp index 83d504f2429..bda2f5c1b74 100644 --- a/searchsummary/src/vespa/searchsummary/docsummary/resultpacker.cpp +++ b/searchsummary/src/vespa/searchsummary/docsummary/resultpacker.cpp @@ -121,6 +121,7 @@ ResultPacker::AddEmpty() case RES_JSONSTRING: case RES_FEATUREDATA: case RES_LONG_STRING: return AddLongString(NULL, 0); + case RES_TENSOR: return AddSerializedTensor(NULL, 0); case RES_LONG_DATA: return AddLongData(NULL, 0); } } @@ -251,6 +252,17 @@ ResultPacker::AddLongData(const char *buf, uint32_t buflen) bool +ResultPacker::AddSerializedTensor(const char *buf, uint32_t buflen) +{ + if (CheckEntry(RES_TENSOR)) { + _buf.append(&buflen, sizeof(buflen)); + _buf.append(buf, buflen); + } + return !_error; +} + + +bool ResultPacker::GetDocsumBlob(const char **buf, uint32_t *buflen) { if (!_error && diff --git a/searchsummary/src/vespa/searchsummary/docsummary/resultpacker.h b/searchsummary/src/vespa/searchsummary/docsummary/resultpacker.h index 8280ebe0980..634084fea6a 100644 --- a/searchsummary/src/vespa/searchsummary/docsummary/resultpacker.h +++ b/searchsummary/src/vespa/searchsummary/docsummary/resultpacker.h @@ -230,6 +230,14 @@ public: **/ bool AddLongData(const char *buf, uint32_t buflen); + /* + * Add a 'tensor' field to the docsum blob we are currently creating. + * + * @return true(ok)/false(error). + * @param buf pointer to serialized tensor to add. + * @param buflen length of serialized tensor to add. + **/ + bool AddSerializedTensor(const char *buf, uint32_t buflen); /** * Obtain a pointer to, and the length of, the created docsum diff --git a/searchsummary/src/vespa/searchsummary/docsummary/urlresult.cpp b/searchsummary/src/vespa/searchsummary/docsummary/urlresult.cpp index 92ebe07d457..47cc0cf3a33 100644 --- a/searchsummary/src/vespa/searchsummary/docsummary/urlresult.cpp +++ b/searchsummary/src/vespa/searchsummary/docsummary/urlresult.cpp @@ -419,6 +419,7 @@ GeneralResult::unpack(const char *buf, const size_t buflen) break; } + case RES_TENSOR: case RES_LONG_DATA: { uint32_t ldlen; |