diff options
author | Arnstein Ressem <aressem@vespa.ai> | 2024-05-03 08:17:14 +0200 |
---|---|---|
committer | Arnstein Ressem <aressem@vespa.ai> | 2024-05-03 08:17:14 +0200 |
commit | 8a042c7e8dddce341e8cff74cb1cc408199e217d (patch) | |
tree | a5dafef1049a854b017f45b382e2fbb8afc4d3eb | |
parent | 8ebebb88ff66fe73dcf98acf0b8c7d7b45a75ee2 (diff) | |
parent | 686cbeafbdf24c3d6a0ffcc3dd79425d4eba6833 (diff) |
Merge branch 'master' into aressem/parameterize-mvn-target
14 files changed, 267 insertions, 151 deletions
diff --git a/container-search/src/main/java/com/yahoo/search/query/SelectParser.java b/container-search/src/main/java/com/yahoo/search/query/SelectParser.java index c90612425fa..90d5e04d2b6 100644 --- a/container-search/src/main/java/com/yahoo/search/query/SelectParser.java +++ b/container-search/src/main/java/com/yahoo/search/query/SelectParser.java @@ -256,26 +256,18 @@ public class SelectParser implements Parser { } private Item buildFunctionCall(String key, Inspector value) { - switch (key) { - case WAND: - return buildWand(key, value); - case WEIGHTED_SET: - return buildWeightedSet(key, value); - case DOT_PRODUCT: - return buildDotProduct(key, value); - case GEO_LOCATION: - return buildGeoLocation(key, value); - case NEAREST_NEIGHBOR: - return buildNearestNeighbor(key, value); - case PREDICATE: - return buildPredicate(key, value); - case RANK: - return buildRank(key, value); - case WEAK_AND: - return buildWeakAnd(key, value); - default: - throw newUnexpectedArgumentException(key, DOT_PRODUCT, NEAREST_NEIGHBOR, RANK, WAND, WEAK_AND, WEIGHTED_SET, PREDICATE); - } + return switch (key) { + case WAND -> buildWand(key, value); + case WEIGHTED_SET -> buildWeightedSet(key, value); + case DOT_PRODUCT -> buildDotProduct(key, value); + case GEO_LOCATION -> buildGeoLocation(key, value); + case NEAREST_NEIGHBOR -> buildNearestNeighbor(key, value); + case PREDICATE -> buildPredicate(key, value); + case RANK -> buildRank(key, value); + case WEAK_AND -> buildWeakAnd(key, value); + default -> + throw newUnexpectedArgumentException(key, DOT_PRODUCT, NEAREST_NEIGHBOR, RANK, WAND, WEAK_AND, WEIGHTED_SET, PREDICATE); + }; } private void addItemsFromInspector(CompositeItem item, Inspector inspector){ @@ -312,15 +304,11 @@ public class SelectParser implements Parser { private HashMap<Integer, Inspector> childMap(Inspector inspector) { HashMap<Integer, Inspector> children = new HashMap<>(); if (inspector.type() == ARRAY){ - inspector.traverse((ArrayTraverser) (index, new_value) -> { - children.put(index, new_value); - }); + inspector.traverse((ArrayTraverser) children::put); } else if (inspector.type() == OBJECT){ if (inspector.field("children").valid()){ - inspector.field("children").traverse((ArrayTraverser) (index, new_value) -> { - children.put(index, new_value); - }); + inspector.field("children").traverse((ArrayTraverser) children::put); } } return children; @@ -336,9 +324,7 @@ public class SelectParser implements Parser { private HashMap<String, Inspector> getAnnotationMapFromAnnotationInspector(Inspector annotation) { HashMap<String, Inspector> attributes = new HashMap<>(); if (annotation.type() == OBJECT){ - annotation.traverse((ObjectTraverser) (index, new_value) -> { - attributes.put(index, new_value); - }); + annotation.traverse((ObjectTraverser) attributes::put); } return attributes; } @@ -346,9 +332,7 @@ public class SelectParser implements Parser { private HashMap<String, Inspector> getAnnotationMap(Inspector inspector) { HashMap<String, Inspector> attributes = new HashMap<>(); if (inspector.type() == OBJECT && inspector.field("attributes").valid()){ - inspector.field("attributes").traverse((ObjectTraverser) (index, new_value) -> { - attributes.put(index, new_value); - }); + inspector.field("attributes").traverse((ObjectTraverser) attributes::put); } return attributes; } @@ -487,7 +471,6 @@ public class SelectParser implements Parser { return item; } - @SuppressWarnings("deprecation") private CompositeItem buildWeakAnd(String key, Inspector value) { WeakAndItem weakAnd = new WeakAndItem(); addItemsFromInspector(weakAnd, value); @@ -576,8 +559,7 @@ public class SelectParser implements Parser { } }); } - if (out instanceof IntItem && annotations != null) { - IntItem number = (IntItem) out; + if (out instanceof IntItem number && annotations != null) { Integer hitLimit = getCappedRangeSearchParameter(annotations); if (hitLimit != null) { number.setHitLimit(hitLimit); @@ -631,12 +613,13 @@ public class SelectParser implements Parser { throw new IllegalArgumentException("The first array element under 'equals' should be a field name string " + "but was " + children.get(0)); String field = children.get(0).asString(); - switch (children.get(1).type()) { - case BOOL: return new BoolItem(children.get(1).asBool(), field); - case LONG: return new IntItem(children.get(1).asLong(), field); - default: throw new IllegalArgumentException("The second array element under 'equals' should be a boolean " + - "or int value but was " + children.get(1)); - } + return switch (children.get(1).type()) { + case BOOL -> new BoolItem(children.get(1).asBool(), field); + case LONG -> new IntItem(children.get(1).asLong(), field); + default -> + throw new IllegalArgumentException("The second array element under 'equals' should be a boolean " + + "or int value but was " + children.get(1)); + }; } private Item buildRange(String key, Inspector value) { @@ -661,15 +644,15 @@ public class SelectParser implements Parser { throw new IllegalArgumentException("Expected a numeric argument to range, but got the string '" + bound.asString() + "'"); } if (operator.equals("=")) { - bounds[0] = (bound.type() == DOUBLE) ? Number.class.cast(bound.asDouble()) : Number.class.cast(bound.asLong()); + bounds[0] = (bound.type() == DOUBLE) ? (Number) bound.asDouble() : (Number) bound.asLong(); operators[0] = operator; equals[0] = true; } if (operator.equals(">=") || operator.equals(">")){ - bounds[0] = (bound.type() == DOUBLE) ? Number.class.cast(bound.asDouble()) : Number.class.cast(bound.asLong()); + bounds[0] = (bound.type() == DOUBLE) ? (Number) bound.asDouble() : (Number) bound.asLong(); operators[0] = operator; } else if (operator.equals("<=") || operator.equals("<")){ - bounds[1] = (bound.type() == DOUBLE) ? Number.class.cast(bound.asDouble()) : Number.class.cast(bound.asLong()); + bounds[1] = (bound.type() == DOUBLE) ? (Number) bound.asDouble() : (Number) bound.asLong(); operators[1] = operator; } @@ -680,20 +663,13 @@ public class SelectParser implements Parser { } else if (operators[0] == null || operators[1] == null) { int index = (operators[0] == null) ? 1 : 0; - switch (operators[index]){ - case ">=": - range = buildGreaterThanOrEquals(field, bounds[index].toString()); - break; - case ">": - range = buildGreaterThan(field, bounds[index].toString()); - break; - case "<": - range = buildLessThan(field, bounds[index].toString()); - break; - case "<=": - range = buildLessThanOrEquals(field, bounds[index].toString()); - break; - } + range = switch (operators[index]) { + case ">=" -> buildGreaterThanOrEquals(field, bounds[index].toString()); + case ">" -> buildGreaterThan(field, bounds[index].toString()); + case "<" -> buildLessThan(field, bounds[index].toString()); + case "<=" -> buildLessThanOrEquals(field, bounds[index].toString()); + default -> range; + }; } else { range = instantiateRangeItem(bounds[0], bounds[1], field, operators[0].equals(">"), operators[1].equals("<")); @@ -890,7 +866,7 @@ public class SelectParser implements Parser { String possibleLeafFunctionName = (possibleLeafFunction.size() > 1) ? getInspectorKey(possibleLeafFunction.get(1)) : ""; if (FUNCTION_CALLS.contains(key)) { return instantiateCompositeLeaf(field, key, value); - } else if ( ! possibleLeafFunctionName.equals("")){ + } else if (!possibleLeafFunctionName.isEmpty()){ return instantiateCompositeLeaf(field, possibleLeafFunctionName, valueListFromInspector(value).get(1).field(possibleLeafFunctionName)); } else { return instantiateWordItem(field, key, value); @@ -898,24 +874,16 @@ public class SelectParser implements Parser { } private Item instantiateCompositeLeaf(String field, String key, Inspector value) { - switch (key) { - case SAME_ELEMENT: - return instantiateSameElementItem(field, key, value); - case PHRASE: - return instantiatePhraseItem(field, key, value); - case NEAR: - return instantiateNearItem(field, key, value); - case ONEAR: - return instantiateONearItem(field, key, value); - case EQUIV: - return instantiateEquivItem(field, key, value); - case FUZZY: - return instantiateFuzzyItem(field, key, value); - case ALTERNATIVES: - return instantiateWordAlternativesItem(field, key, value); - default: - throw newUnexpectedArgumentException(key, EQUIV, NEAR, ONEAR, PHRASE, SAME_ELEMENT); - } + return switch (key) { + case SAME_ELEMENT -> instantiateSameElementItem(field, key, value); + case PHRASE -> instantiatePhraseItem(field, key, value); + case NEAR -> instantiateNearItem(field, key, value); + case ONEAR -> instantiateONearItem(field, key, value); + case EQUIV -> instantiateEquivItem(field, key, value); + case FUZZY -> instantiateFuzzyItem(field, key, value); + case ALTERNATIVES -> instantiateWordAlternativesItem(field, key, value); + default -> throw newUnexpectedArgumentException(key, EQUIV, NEAR, ONEAR, PHRASE, SAME_ELEMENT); + }; } private Item instantiateWordItem(String field, String key, Inspector value) { @@ -944,8 +912,8 @@ public class SelectParser implements Parser { Preconditions.checkArgument((prefixMatch ? 1 : 0) + (substrMatch ? 1 : 0) + (suffixMatch ? 1 : 0) < 2, "Only one of prefix, substring and suffix can be set."); - final TaggableItem wordItem; + WordItem wordItem; if (exactMatch) { wordItem = new ExactStringItem(wordData, fromQuery); } else if (prefixMatch) { @@ -958,13 +926,11 @@ public class SelectParser implements Parser { wordItem = new WordItem(wordData, fromQuery); } - if (wordItem instanceof WordItem) { - prepareWord(field, value, (WordItem) wordItem); - } + prepareWord(field, value, wordItem); if (language != Language.ENGLISH) - ((Item)wordItem).setLanguage(language); + wordItem.setLanguage(language); - return (Item) leafStyleSettings(getAnnotations(value), wordItem); + return leafStyleSettings(getAnnotations(value), wordItem); } private Language decideParsingLanguage(Inspector value, String wordData) { @@ -974,9 +940,8 @@ public class SelectParser implements Parser { if (language != Language.UNKNOWN) return language; Optional<Language> explicitLanguage = query.getExplicitLanguage(); - if (explicitLanguage.isPresent()) return explicitLanguage.get(); + return explicitLanguage.orElse(Language.ENGLISH); - return Language.ENGLISH; } private void prepareWord(String field, Inspector value, WordItem wordItem) { @@ -1094,7 +1059,7 @@ public class SelectParser implements Parser { Integer distance = getIntegerAnnotation(DISTANCE, getAnnotationMap(value), null); if (distance != null) { - near.setDistance((int)distance); + near.setDistance(distance); } return near; } @@ -1120,7 +1085,8 @@ public class SelectParser implements Parser { private Item instantiateEquivItem(String field, String key, Inspector value) { HashMap<Integer, Inspector> children = childMap(value); - Preconditions.checkArgument(children.size() >= 2, "Expected 2 or more arguments, got %s.", children.size()); + Preconditions.checkArgument(children.size() >= 2, + "Expected 2 or more arguments, got %s.", children.size()); EquivItem equiv = new EquivItem(); equiv.setIndexName(field); @@ -1159,8 +1125,9 @@ public class SelectParser implements Parser { private Item instantiateWordAlternativesItem(String field, String key, Inspector value) { HashMap<Integer, Inspector> children = childMap(value); - Preconditions.checkArgument(children.size() >= 1, "Expected 1 or more arguments, got %s.", children.size()); - Preconditions.checkArgument(children.get(0).type() == OBJECT, "Expected OBJECT, got %s.", children.get(0).type()); + Preconditions.checkArgument(!children.isEmpty(), "Expected 1 or more arguments, got none"); + Preconditions.checkArgument(children.get(0).type() == OBJECT, + "Expected OBJECT, got %s.", children.get(0).type()); List<WordAlternativesItem.Alternative> terms = new ArrayList<>(); diff --git a/container-search/src/test/java/com/yahoo/select/SelectTestCase.java b/container-search/src/test/java/com/yahoo/select/SelectTestCase.java index f863816dab2..b15663e0ce6 100644 --- a/container-search/src/test/java/com/yahoo/select/SelectTestCase.java +++ b/container-search/src/test/java/com/yahoo/select/SelectTestCase.java @@ -56,6 +56,11 @@ public class SelectTestCase { //------------------------------------------------------------------- "where" tests @Test + void testSimple() { + assertParse("{'contains' : ['title', 'madonna']}", "title:madonna"); + } + + @Test void test_contains() { ObjectNode json = jsonMapper.createObjectNode(); ArrayNode arrayNode = jsonMapper.createArrayNode(); @@ -65,16 +70,9 @@ public class SelectTestCase { } @Test - void test() { - assertParse("{'contains' : ['title', 'madonna']}", - "title:madonna"); - } - - - @Test void testDottedFieldNames() { assertParse("{ 'contains' : ['my.nested.title', 'madonna']}", - "my.nested.title:madonna"); + "my.nested.title:madonna"); } @Test @@ -360,12 +358,12 @@ public class SelectTestCase { @Test void testRaw() { Item root = parseWhere("{ \"contains\":[ \"baz\", \"yoni jo dima\" ] }").getRoot(); - assertTrue(root instanceof WordItem); + assertInstanceOf(WordItem.class, root); assertFalse(root instanceof ExactStringItem); assertEquals("yoni jo dima", ((WordItem) root).getWord()); root = parseWhere("{ \"contains\": { \"children\" : [\"baz\", \"yoni jo dima\"], \"attributes\" : {\"grammar\" : \"raw\"} } }").getRoot(); - assertTrue(root instanceof WordItem); + assertInstanceOf(WordItem.class, root); assertFalse(root instanceof ExactStringItem); assertEquals("yoni jo dima", ((WordItem) root).getWord()); } diff --git a/dist/vespa.spec b/dist/vespa.spec index d7f5fe12a74..2e6e3c042d2 100644 --- a/dist/vespa.spec +++ b/dist/vespa.spec @@ -33,11 +33,13 @@ %define _defattr_is_vespa_vespa 0 %define _command_cmake cmake3 %global _vespa_abseil_cpp_version 20240116.1 -%global _vespa_build_depencencies_version 1.3.1 +%global _vespa_build_depencencies_version 1.3.2 %global _vespa_gtest_version 1.14.0 %global _vespa_protobuf_version 5.26.1 +%global _vespa_openblas_version 0.3.27 %global _use_vespa_abseil_cpp 1 %global _use_vespa_protobuf 1 +%global _use_vespa_openblas 1 Name: vespa Version: _VESPA_VERSION_ @@ -77,7 +79,6 @@ Requires: zstd %define _devtoolset_enable /opt/rh/gcc-toolset/enable %define _use_vespa_gtest 1 -%define _use_vespa_openblas 1 %define _use_vespa_openssl 1 %if 0%{?centos} || 0%{?rocky} || 0%{?oraclelinux} @@ -163,11 +164,7 @@ Requires: openssl-libs %endif Requires: vespa-lz4 >= 1.9.4-1 Requires: vespa-libzstd >= 1.5.6-1 -%if 0%{?el8} -Requires: vespa-openblas >= 0.3.27 -%else -Requires: openblas-serial -%endif +Requires: vespa-openblas >= %{_vespa_openblas_version} %if 0%{?amzn2023} Requires: vespa-re2 = 20210801 %else diff --git a/document/src/main/java/com/yahoo/document/DocumentUpdate.java b/document/src/main/java/com/yahoo/document/DocumentUpdate.java index 20d9b352d2d..d8d8c02c43b 100644 --- a/document/src/main/java/com/yahoo/document/DocumentUpdate.java +++ b/document/src/main/java/com/yahoo/document/DocumentUpdate.java @@ -188,13 +188,8 @@ public class DocumentUpdate extends DocumentOperation implements Iterable<FieldP return Collections.unmodifiableCollection(fieldPathUpdates); } - /** Returns the type of the document this updates - * - * @return The document type of the document - */ - public DocumentType getDocumentType() { - return documentType; - } + /** Returns the type of the document this updates. */ + public DocumentType getDocumentType() { return documentType; } /** * Sets the document type. Use only while deserializing - changing the document type after creation diff --git a/document/src/test/java/com/yahoo/document/DocumentUpdateTestCase.java b/document/src/test/java/com/yahoo/document/DocumentUpdateTestCase.java index 7be50b58b61..bd977520b66 100644 --- a/document/src/test/java/com/yahoo/document/DocumentUpdateTestCase.java +++ b/document/src/test/java/com/yahoo/document/DocumentUpdateTestCase.java @@ -270,7 +270,6 @@ public class DocumentUpdateTestCase { DocumentUpdate update = new DocumentUpdate(docType, new DocumentId("id:ns:my_type::foo:")); update.addFieldUpdate(FieldUpdate.createAssign(field, new IntegerFieldValue(1))); update.addFieldUpdate(FieldUpdate.createAssign(field, new IntegerFieldValue(2))); - assertEquals(1, update.fieldUpdates().size()); FieldUpdate fieldUpdate = update.getFieldUpdate(field); assertNotNull(fieldUpdate); diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java index d2f1d5fb66c..7ebe9555296 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java @@ -91,7 +91,7 @@ public class Flags { "Takes effect on next deployment of an applications."); public static final UnboundBooleanFlag FIX_CONFIG_SERVER_HEAP = defineFeatureFlag( - "fix-config-server-heap", false, + "fix-config-server-heap", true, List.of("hakonhall"), "2024-04-23", "2024-05-23", "Base the calculation of the config server JVM heap size on the amount of memory available to the container.", "Takes effect on start of config server Podman container"); @@ -418,13 +418,13 @@ public class Flags { public static UnboundBooleanFlag CALYPSO_ENABLED = defineFeatureFlag( "calypso-enabled", true, - List.of("mortent"), "2024-02-19", "2024-05-01", + List.of("mortent"), "2024-02-19", "2024-08-01", "Whether to enable calypso for host", "Takes effect immediately", HOSTNAME); public static UnboundBooleanFlag ATHENZ_PROVIDER = defineFeatureFlag( "athenz-provider", false, - List.of("mortent"), "2024-02-19", "2024-05-01", + List.of("mortent"), "2024-02-19", "2024-08-01", "Whether to use athenz as node identity provider", "Takes effect on next identity refresh", HOSTNAME); diff --git a/integration/intellij/src/main/java/ai/vespa/intellij/schema/SdSyntaxHighlighter.java b/integration/intellij/src/main/java/ai/vespa/intellij/schema/SdSyntaxHighlighter.java index a5387a87aee..f16ea512a45 100644 --- a/integration/intellij/src/main/java/ai/vespa/intellij/schema/SdSyntaxHighlighter.java +++ b/integration/intellij/src/main/java/ai/vespa/intellij/schema/SdSyntaxHighlighter.java @@ -102,6 +102,7 @@ public class SdSyntaxHighlighter extends SyntaxHighlighterBase { keyWords.add(SdTypes.ONNX_MODEL); keyWords.add(SdTypes.ANNOTATION); keyWords.add(SdTypes.RANK_PROFILE); + keyWords.add(SdTypes.SIGNIFICANCE); keyWords.add(SdTypes.MATCH_PHASE); keyWords.add(SdTypes.FIRST_PHASE); keyWords.add(SdTypes.EXPRESSION); diff --git a/integration/intellij/src/main/jflex/ai/vespa/intellij/schema/lexer/sd.flex b/integration/intellij/src/main/jflex/ai/vespa/intellij/schema/lexer/sd.flex index 47050479633..2e80be34fc2 100644 --- a/integration/intellij/src/main/jflex/ai/vespa/intellij/schema/lexer/sd.flex +++ b/integration/intellij/src/main/jflex/ai/vespa/intellij/schema/lexer/sd.flex @@ -149,7 +149,8 @@ WORD = \w+ "strict" { return STRICT; } "rank-properties" { return RANK_PROPERTIES; } "inputs" { return INPUTS; } - + + "significance" { return SIGNIFICANCE; } "first-phase" { return FIRST_PHASE; } "keep-rank-count" { return KEEP_RANK_COUNT; } "rank-score-drop-limit" { return RANK_SCORE_DROP_LIMIT; } diff --git a/searchcore/src/tests/proton/attribute/attributes_state_explorer/attributes_state_explorer_test.cpp b/searchcore/src/tests/proton/attribute/attributes_state_explorer/attributes_state_explorer_test.cpp index fd202c24887..732a95e7c13 100644 --- a/searchcore/src/tests/proton/attribute/attributes_state_explorer/attributes_state_explorer_test.cpp +++ b/searchcore/src/tests/proton/attribute/attributes_state_explorer/attributes_state_explorer_test.cpp @@ -2,11 +2,19 @@ #include <vespa/searchcore/proton/attribute/attribute_manager_explorer.h> #include <vespa/searchcore/proton/attribute/attributemanager.h> +#include <vespa/searchcore/proton/attribute/imported_attributes_repo.h> +#include <vespa/searchcore/proton/bucketdb/bucket_db_owner.h> +#include <vespa/searchcore/proton/documentmetastore/documentmetastorecontext.h> #include <vespa/searchcore/proton/test/attribute_utils.h> #include <vespa/searchcore/proton/test/attribute_vectors.h> +#include <vespa/searchlib/attribute/attributefactory.h> +#include <vespa/searchlib/attribute/imported_attribute_vector.h> +#include <vespa/searchlib/attribute/imported_attribute_vector_factory.h> #include <vespa/searchlib/attribute/interlock.h> +#include <vespa/searchlib/attribute/reference_attribute.h> #include <vespa/searchlib/index/dummyfileheadercontext.h> #include <vespa/searchlib/test/directory_handler.h> +#include <vespa/searchlib/test/mock_gid_to_lid_mapping.h> #include <vespa/searchcommon/attribute/config.h> #include <vespa/vespalib/data/slime/slime.h> #include <vespa/vespalib/gtest/gtest.h> @@ -21,6 +29,12 @@ using namespace proton; using namespace proton::test; using search::AttributeVector; using search::DictionaryConfig; +using search::attribute::BasicType; +using search::attribute::Config; +using search::attribute::ImportedAttributeVector; +using search::attribute::ImportedAttributeVectorFactory; +using search::attribute::ReferenceAttribute; +using search::attribute::test::MockGidToLidMapperFactory; using vespalib::ForegroundThreadExecutor; using vespalib::ISequencedTaskExecutor; using vespalib::SequencedTaskExecutor; @@ -32,6 +46,10 @@ using vespalib::HwInfo; const vespalib::string TEST_DIR = "test_output"; +const vespalib::string ref_name("ref"); +const vespalib::string target_name("f3"); +const vespalib::string imported_name("my_f3"); + namespace { VESPA_THREAD_STACK_TAG(test_executor) } @@ -43,28 +61,13 @@ struct AttributesStateExplorerTest : public ::testing::Test std::unique_ptr<ISequencedTaskExecutor> _attribute_field_writer; ForegroundThreadExecutor _shared; HwInfo _hwInfo; + std::shared_ptr<const IDocumentMetaStoreContext> _parent_dms; + std::shared_ptr<IDocumentMetaStoreContext> _dms; + std::shared_ptr<AttributeManager> _parent_mgr; AttributeManager::SP _mgr; AttributeManagerExplorer _explorer; - AttributesStateExplorerTest() - : _dirHandler(TEST_DIR), - _fileHeaderContext(), - _attribute_field_writer(SequencedTaskExecutor::create(test_executor, 1)), - _shared(), - _hwInfo(), - _mgr(new AttributeManager(TEST_DIR, "test.subdb", TuneFileAttributes(), - _fileHeaderContext, - std::make_shared<search::attribute::Interlock>(), - *_attribute_field_writer, - _shared, - _hwInfo)), - _explorer(_mgr) - { - addAttribute("regular"); - addExtraAttribute("extra"); - add_fast_search_attribute("btree", DictionaryConfig::Type::BTREE); - add_fast_search_attribute("hybrid", DictionaryConfig::Type::BTREE_AND_HASH); - add_fast_search_attribute("hash", DictionaryConfig::Type::HASH); - } + AttributesStateExplorerTest() noexcept; + ~AttributesStateExplorerTest() override; void addAttribute(const vespalib::string &name) { _mgr->addAttribute({name, AttributeUtils::getInt32Config()}, 1); } @@ -84,16 +87,71 @@ struct AttributesStateExplorerTest : public ::testing::Test _explorer.get_child(name)->get_state(inserter, true); return result; } - + void add_reference_attribute() { + search::attribute::Config cfg(BasicType::REFERENCE); + _mgr->addAttribute({ ref_name, cfg }, 1); + auto& ref_attr = dynamic_cast<ReferenceAttribute&>(**_mgr->getAttribute(ref_name)); + ref_attr.setGidToLidMapperFactory(std::make_shared<MockGidToLidMapperFactory>()); + } + std::shared_ptr<ReferenceAttribute> get_reference_attribute() { + return std::dynamic_pointer_cast<ReferenceAttribute>(_mgr->getAttribute(ref_name)->getSP()); + } + void add_imported_attributes() { + auto repo = std::make_unique<ImportedAttributesRepo>(); + auto attr = ImportedAttributeVectorFactory::create(imported_name, + get_reference_attribute(), + _dms, + _parent_mgr->getAttribute(target_name)->getSP(), + _parent_dms, + false); + repo->add(imported_name, attr); + _mgr->setImportedAttributes(std::move(repo)); + } }; +AttributesStateExplorerTest::AttributesStateExplorerTest() noexcept + : _dirHandler(TEST_DIR), + _fileHeaderContext(), + _attribute_field_writer(SequencedTaskExecutor::create(test_executor, 1)), + _shared(), + _hwInfo(), + _parent_dms(std::make_shared<const DocumentMetaStoreContext>(std::make_shared<bucketdb::BucketDBOwner>())), + _dms(), + _parent_mgr(std::make_shared<AttributeManager> + (TEST_DIR, "test.parent.subdb", TuneFileAttributes(), + _fileHeaderContext, + std::make_shared<search::attribute::Interlock>(), + *_attribute_field_writer, + _shared, + _hwInfo)), + _mgr(new AttributeManager(TEST_DIR, "test.subdb", TuneFileAttributes(), + _fileHeaderContext, + std::make_shared<search::attribute::Interlock>(), + *_attribute_field_writer, + _shared, + _hwInfo)), + _explorer(_mgr) +{ + _parent_mgr->addAttribute({target_name, AttributeUtils::getInt32Config()}, 1); + addAttribute("regular"); + addExtraAttribute("extra"); + add_fast_search_attribute("btree", DictionaryConfig::Type::BTREE); + add_fast_search_attribute("hybrid", DictionaryConfig::Type::BTREE_AND_HASH); + add_fast_search_attribute("hash", DictionaryConfig::Type::HASH); + add_reference_attribute(); + add_imported_attributes(); +} + +AttributesStateExplorerTest::~AttributesStateExplorerTest() = default; + + using StringVector = std::vector<vespalib::string>; TEST_F(AttributesStateExplorerTest, require_that_attributes_are_exposed_as_children_names) { StringVector children = _explorer.get_children_names(); std::sort(children.begin(), children.end()); - EXPECT_EQ(StringVector({"btree", "hash", "hybrid", "regular"}), children); + EXPECT_EQ(StringVector({"btree", "hash", "hybrid", "my_f3", "ref", "regular"}), children); } TEST_F(AttributesStateExplorerTest, require_that_attributes_are_explorable) @@ -125,4 +183,12 @@ TEST_F(AttributesStateExplorerTest, require_that_dictionary_memory_usage_is_repo } } +TEST_F(AttributesStateExplorerTest, require_that_imported_attribute_shows_memory_usage) +{ + vespalib::string cache_memory_usage("cacheMemoryUsage"); + auto slime = explore_attribute(imported_name); + EXPECT_LT(0, slime[cache_memory_usage]["allocated"].asLong()); + EXPECT_LT(0, slime[cache_memory_usage]["used"].asLong()); +} + GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchcore/src/vespa/searchcore/proton/attribute/CMakeLists.txt b/searchcore/src/vespa/searchcore/proton/attribute/CMakeLists.txt index 3717c24650d..c1f10ebd80d 100644 --- a/searchcore/src/vespa/searchcore/proton/attribute/CMakeLists.txt +++ b/searchcore/src/vespa/searchcore/proton/attribute/CMakeLists.txt @@ -34,6 +34,7 @@ vespa_add_library(searchcore_attribute STATIC document_field_retriever.cpp filter_attribute_manager.cpp flushableattribute.cpp + imported_attribute_vector_explorer.cpp imported_attributes_context.cpp imported_attributes_repo.cpp initialized_attributes_result.cpp diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_explorer.cpp b/searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_explorer.cpp index 0b48afe4ab8..0797ddfb6cd 100644 --- a/searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_explorer.cpp +++ b/searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_explorer.cpp @@ -3,9 +3,13 @@ #include "attribute_manager_explorer.h" #include "attribute_executor.h" #include "attribute_vector_explorer.h" +#include "imported_attribute_vector_explorer.h" +#include "imported_attributes_repo.h" #include <vespa/searchlib/attribute/attributevector.h> +#include <vespa/searchlib/attribute/imported_attribute_vector.h> using search::AttributeVector; +using search::attribute::ImportedAttributeVector; using vespalib::slime::Inserter; namespace proton { @@ -32,6 +36,14 @@ AttributeManagerExplorer::get_children_names() const for (const auto &attr : attributes) { names.push_back(attr->getName()); } + auto imported = _mgr->getImportedAttributes(); + if (imported != nullptr) { + std::vector<std::shared_ptr<ImportedAttributeVector>> i_list; + imported->getAll(i_list); + for (const auto& attr : i_list) { + names.push_back(attr->getName()); + } + } return names; } @@ -39,6 +51,15 @@ std::unique_ptr<vespalib::StateExplorer> AttributeManagerExplorer::get_child(vespalib::stringref name) const { auto guard = _mgr->getAttribute(name); + if (!guard || !guard->getSP()) { + auto imported = _mgr->getImportedAttributes(); + if (imported != nullptr) { + auto& imported_attr = imported->get(name); + if (imported_attr) { + return std::make_unique<ImportedAttributeVectorExplorer>(imported_attr); + } + } + } auto attr = guard ? guard->getSP() : std::shared_ptr<AttributeVector>(); if (attr && _mgr->getWritableAttribute(name) != nullptr) { auto executor = std::make_unique<AttributeExecutor>(_mgr, std::move(attr)); diff --git a/searchcore/src/vespa/searchcore/proton/attribute/imported_attribute_vector_explorer.cpp b/searchcore/src/vespa/searchcore/proton/attribute/imported_attribute_vector_explorer.cpp new file mode 100644 index 00000000000..dd858b78934 --- /dev/null +++ b/searchcore/src/vespa/searchcore/proton/attribute/imported_attribute_vector_explorer.cpp @@ -0,0 +1,28 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "imported_attribute_vector_explorer.h" +#include <vespa/searchlib/attribute/imported_attribute_vector.h> +#include <vespa/searchlib/util/state_explorer_utils.h> +#include <vespa/vespalib/data/slime/cursor.h> +#include <vespa/vespalib/util/memoryusage.h> + +using search::StateExplorerUtils; +using search::attribute::ImportedAttributeVector; +using namespace vespalib::slime; + +namespace proton { + +ImportedAttributeVectorExplorer::ImportedAttributeVectorExplorer(std::shared_ptr<ImportedAttributeVector> attr) + : _attr(std::move(attr)) +{ +} + +void +ImportedAttributeVectorExplorer::get_state(const vespalib::slime::Inserter &inserter, bool) const +{ + Cursor &object = inserter.insertObject(); + auto memory_usage = _attr->get_memory_usage(); + StateExplorerUtils::memory_usage_to_slime(memory_usage, object.setObject("cacheMemoryUsage")); +} + +} diff --git a/searchcore/src/vespa/searchcore/proton/attribute/imported_attribute_vector_explorer.h b/searchcore/src/vespa/searchcore/proton/attribute/imported_attribute_vector_explorer.h new file mode 100644 index 00000000000..ce8854b03d2 --- /dev/null +++ b/searchcore/src/vespa/searchcore/proton/attribute/imported_attribute_vector_explorer.h @@ -0,0 +1,26 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#pragma once + +#include <vespa/vespalib/net/http/state_explorer.h> + +namespace search::attribute { class ImportedAttributeVector; } + +namespace proton { + +/** + * Class used to explore the state of an imported attribute vector. + */ +class ImportedAttributeVectorExplorer : public vespalib::StateExplorer +{ +private: + std::shared_ptr<search::attribute::ImportedAttributeVector> _attr; + +public: + ImportedAttributeVectorExplorer(std::shared_ptr<search::attribute::ImportedAttributeVector> attr); + + // Implements vespalib::StateExplorer + void get_state(const vespalib::slime::Inserter &inserter, bool full) const override; +}; + +} diff --git a/searchlib/src/tests/queryeval/iterator_benchmark/iterator_benchmark_test.cpp b/searchlib/src/tests/queryeval/iterator_benchmark/iterator_benchmark_test.cpp index d8fcd613fc3..2977664f6ad 100644 --- a/searchlib/src/tests/queryeval/iterator_benchmark/iterator_benchmark_test.cpp +++ b/searchlib/src/tests/queryeval/iterator_benchmark/iterator_benchmark_test.cpp @@ -318,26 +318,26 @@ struct Sample { } }; -double find_crossover(const char *type, const auto &calculate_at, double delta) { +double find_crossover(const char *type, const char *a, const char *b, const auto &calculate_at, double delta) { double min = delta; double max = 1.0; fprintf(stderr, "looking for %s crossover in the range [%g, %g]...\n", type, min, max); auto at_min = calculate_at(min); auto at_max = calculate_at(max); - fprintf(stderr, " before: [%s, %s], after: [%s, %s]\n", - at_min.first.str().c_str(), at_max.first.str().c_str(), - at_min.second.str().c_str(), at_max.second.str().c_str()); - auto best_before = [](auto values) { return (values.first < values.second); }; - if (best_before(at_min) == best_before(at_max)) { + fprintf(stderr, " %s: [%s, %s], %s: [%s, %s]\n", + a, at_min.first.str().c_str(), at_max.first.str().c_str(), + b, at_min.second.str().c_str(), at_max.second.str().c_str()); + auto a_best = [](auto values) { return (values.first < values.second); }; + if (a_best(at_min) == a_best(at_max)) { fprintf(stderr, " NO %s CROSSOVER FOUND\n", type); return 0.0; } while (max > (min + delta)) { double x = (min + max) / 2.0; auto at_x = calculate_at(x); - fprintf(stderr, " best@%g: %s (%s vs %s)\n", x, best_before(at_x) ? "before" : "after", + fprintf(stderr, " best@%g: %s (%s vs %s)\n", x, a_best(at_x) ? a : b, at_x.first.str().c_str(), at_x.second.str().c_str()); - if (best_before(at_min) == best_before(at_x)) { + if (a_best(at_min) == a_best(at_x)) { min = x; at_min = at_x; } else { @@ -410,11 +410,11 @@ void analyze_crossover(BenchmarkBlueprintFactory &fixed, std::function<std::uniq std::vector<double> results; std::vector<const char *> names; names.push_back("time crossover"); - results.push_back(find_crossover("TIME", combine(estimate_AND_time_ms), delta)); + results.push_back(find_crossover("TIME", "before", "after", combine(estimate_AND_time_ms), delta)); names.push_back("cost crossover"); - results.push_back(find_crossover("COST", combine(calculate_AND_cost), delta)); + results.push_back(find_crossover("COST", "before", "after", combine(calculate_AND_cost), delta)); names.push_back("abs_est crossover"); - results.push_back(find_crossover("ABS_EST", combine(first_abs_est), delta)); + results.push_back(find_crossover("ABS_EST", "before", "after", combine(first_abs_est), delta)); sample_at("COST", combine(calculate_AND_cost), results, names); sample_at("TIME", combine(estimate_AND_time_ms), results, names); } @@ -1026,6 +1026,22 @@ TEST(IteratorBenchmark, analyze_btree_vs_bitvector_iterators_strict) run_benchmarks(setup); } +TEST(IteratorBenchmark, btree_vs_array_nonstrict_crossover) { + for (double hit_ratio: { 0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.009, + 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, + 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, + 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.0}) + { + auto btree = make_blueprint_factory(int32_array_fs, QueryOperator::Term, num_docs, 0, hit_ratio, 1, false); + auto array = make_blueprint_factory( int32_array, QueryOperator::Term, num_docs, 0, hit_ratio, 1, false); + auto time_ms = [&](auto &bpf, double in_flow) { + return Sample(benchmark_search(bpf, num_docs + 1, false, false, false, in_flow, PlanningAlgo::Cost).time_ms); + }; + auto calculate_at = [&](double in_flow) { return std::make_pair(time_ms(*btree, in_flow), time_ms(*array, in_flow)); }; + fprintf(stderr, "btree/array crossover@%5.3f: %8.6f\n", hit_ratio, find_crossover("TIME", "btree", "array", calculate_at, 0.0001)); + } +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); int res = RUN_ALL_TESTS(); |