summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnstein Ressem <aressem@vespa.ai>2024-05-03 08:17:14 +0200
committerArnstein Ressem <aressem@vespa.ai>2024-05-03 08:17:14 +0200
commit8a042c7e8dddce341e8cff74cb1cc408199e217d (patch)
treea5dafef1049a854b017f45b382e2fbb8afc4d3eb
parent8ebebb88ff66fe73dcf98acf0b8c7d7b45a75ee2 (diff)
parent686cbeafbdf24c3d6a0ffcc3dd79425d4eba6833 (diff)
Merge branch 'master' into aressem/parameterize-mvn-target
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/SelectParser.java145
-rw-r--r--container-search/src/test/java/com/yahoo/select/SelectTestCase.java18
-rw-r--r--dist/vespa.spec11
-rw-r--r--document/src/main/java/com/yahoo/document/DocumentUpdate.java9
-rw-r--r--document/src/test/java/com/yahoo/document/DocumentUpdateTestCase.java1
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/Flags.java6
-rw-r--r--integration/intellij/src/main/java/ai/vespa/intellij/schema/SdSyntaxHighlighter.java1
-rw-r--r--integration/intellij/src/main/jflex/ai/vespa/intellij/schema/lexer/sd.flex3
-rw-r--r--searchcore/src/tests/proton/attribute/attributes_state_explorer/attributes_state_explorer_test.cpp110
-rw-r--r--searchcore/src/vespa/searchcore/proton/attribute/CMakeLists.txt1
-rw-r--r--searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_explorer.cpp21
-rw-r--r--searchcore/src/vespa/searchcore/proton/attribute/imported_attribute_vector_explorer.cpp28
-rw-r--r--searchcore/src/vespa/searchcore/proton/attribute/imported_attribute_vector_explorer.h26
-rw-r--r--searchlib/src/tests/queryeval/iterator_benchmark/iterator_benchmark_test.cpp38
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();