From 663857adef00c33b7084c44d02f70a83c5099956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6ker?= Date: Fri, 13 Mar 2026 05:13:31 +0000 Subject: [PATCH 1/4] Refactor test for elementFilter annotation --- .../element_filter_annotation.rb | 276 +++++++++--------- 1 file changed, 138 insertions(+), 138 deletions(-) diff --git a/tests/search/same_element_operator/element_filter_annotation.rb b/tests/search/same_element_operator/element_filter_annotation.rb index d2bf702be..46409160f 100644 --- a/tests/search/same_element_operator/element_filter_annotation.rb +++ b/tests/search/same_element_operator/element_filter_annotation.rb @@ -5,12 +5,23 @@ class ElementFilterAnnotation < IndexedStreamingSearchTest + ###################################################################################################################### + # Test setup + ###################################################################################################################### + def setup set_owner('boeker') # This test uses the elementFilter annotation of the sameElement operator to limit it to specific ids, # effectively indexing the array at the specified positions. end + # Takes a hash of the form {"first_array_name" => [foo_array_first_doc, foo_array_second_doc], + # "second_array_name" => [bar_array_first_doc, bar_array_second_doc], + # ...} + # and turns it into documents: + # The first document has foo_array_first_doc as its array for field "first_array_name" and + # bar_array_first_doc as its array for field "second_array_name" + # ... def feed_docs(array_hash) # Get length of longest array max_length = 0 @@ -38,83 +49,30 @@ def feed_docs(array_hash) wait_for_hitcount("?query=sddocname:arrays", max_length) end - def assert_docs(match_condition, expected_docids) - query = {'yql' => "select * from sources * where #{match_condition} order by id asc"} - result = search(query) - assert_docs_result(expected_docids, result) - end - - def assert_docs_result(expected_docids, result) - assert_hitcount(result, expected_docids.length) - for i in 0...expected_docids.length do - assert_field_value(result, "documentid", "id:arrays:arrays::#{expected_docids[i]}", i) - end - end + ###################################################################################################################### + # Matching test + ###################################################################################################################### - # Returns all query variants that should produce the same result for a given - # array field, element filter indices, and match value. - def build_queries(array_name, indices, value) - queries = [] - if indices.empty? - queries << "#{array_name} contains sameElement(\"#{value}\")" - queries << "#{array_name} contains ({elementFilter:[]}sameElement(\"#{value}\"))" - else - queries << "#{array_name} contains ({elementFilter:[#{indices.join(',')}]}sameElement(\"#{value}\"))" - if indices.length == 1 - queries << "#{array_name} contains ({elementFilter:#{indices[0]}}sameElement(\"#{value}\"))" - - # syntax sugar: field[index] = value - queries << "#{array_name}[#{indices[0]}]=#{add_quotes_if_string(value)}" - end - end - queries - end - - def add_quotes_if_string(s) - return s if ["true", "false"].include?(s) - return s if is_number(s) - "\"#{s}\"" - end - - def is_number(s) - s.match?(/\A-?\d+(\.\d+)?\z/) - end - - def to_native_value(s) - return true if s == "true" - return false if s == "false" - return s.to_i if is_number(s) - s - end - - def post_json_select(query_body) - json = { "select" => { "where" => query_body } } - json["streaming.selection"] = "true" if is_streaming - json["sorting"] = "id" - json["timeout"] = 5 - vespa.container.values.first.post_search( - "/search/", json.to_json, 0, {'Content-Type' => 'application/json'}) - end - - def assert_element_filter(array_name, indices, expected_docids, value) - build_queries(array_name, indices, value).each do |query| - assert_docs(query, expected_docids) - end - if indices.length == 1 - query_body = { "equals" => { "field" => array_name, "index" => indices[0], "value" => to_native_value(value) } } - result = post_json_select(query_body) - assert_docs_result(expected_docids, result) - end - end - - - def test_bool_array - set_description('Use elementFilter annotation of sameElement operator for indexing array of bools.') + def test_matching + set_description('Use elementFilter annotation of sameElement operator for indexing arrays of various data types.') deploy_app(SearchApp.new.sd(selfdir+'arrays.sd')) start - feed_docs({"bool_array" => [[true, true, false], [false, false, true], [true, false, false], [false, true, false], [false, false, false]]}) + bool_arrays = [[true, true, false], [false, false, true], [true, false, false], [false, true, false], [false, false, false]] + int_arrays = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [9, 5, 4], [9, 9, 9]] + float_arrays = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0], [9.0, 5.0, 4.0], [9.0, 9.0, 9.0]] + string_arrays = [["foo", "bar", "baz"], ["foo", "bar", "bar"], ["foo", "foo", "foo"], ["bar", "bar", "foo"], ["baz", "baz", "baz"]] + feed_docs({"bool_array" => bool_arrays, "string_array" => string_arrays, + "byte_array" => int_arrays, "int_array" => int_arrays, "long_array" => int_arrays, + "float_array" => float_arrays, "double_array" => float_arrays}) + + assert_matching_bool_array + assert_matching_string_array + assert_matching_integer_arrays + # Float matching is not possible, string gets tokenized + end + def assert_matching_bool_array # [array, indices, expected_docids, value] [ ["bool_array", [0], [0, 2], "true"], @@ -139,14 +97,7 @@ def test_bool_array end end - - def test_string_array - set_description('Use elementFilter annotation of sameElement operator for indexing array of strings.') - deploy_app(SearchApp.new.sd(selfdir+'arrays.sd')) - start - - feed_docs({"string_array" => [["foo", "bar", "baz"], ["foo", "bar", "bar"], ["foo", "foo", "foo"], ["bar", "bar", "foo"], ["baz", "baz", "baz"]]}) - + def assert_matching_string_array # [array, indices, expected_docids, value] [ ["string_array", [], [0, 4], "baz"], @@ -167,17 +118,7 @@ def test_string_array end end - - def test_numerical_arrays - set_description('Use elementFilter annotation of sameElement operator for indexing arrays of numbers.') - deploy_app(SearchApp.new.sd(selfdir+'arrays.sd')) - start - - int_arrays = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [9, 5, 4], [9, 9, 9]] - float_arrays = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0], [9.0, 5.0, 4.0], [9.0, 9.0, 9.0]] - - feed_docs({"byte_array" => int_arrays, "int_array" => int_arrays, "long_array" => int_arrays, "float_array" => float_arrays, "double_array" => float_arrays}) - + def assert_matching_integer_arrays # [indices, expected_docids, value] test_data = [ [[], [2, 3, 4], "9"], @@ -205,62 +146,123 @@ def test_numerical_arrays assert_element_filter(array_name, indices, expected_docids, value) end end + end + + def assert_element_filter(array_name, indices, expected_docids, value) + build_queries(array_name, indices, value).each do |query| + assert_docs(query, expected_docids) + end + if indices.length == 1 + query_body = { "equals" => { "field" => array_name, "index" => indices[0], "value" => to_native_value(value) } } + result = post_json_select(query_body) + assert_docs_result(expected_docids, result) + end + end + + def to_native_value(s) + return true if s == "true" + return false if s == "false" + return s.to_i if is_number(s) + s + end + + # Returns all query variants that should produce the same result for a given + # array field, element filter indices, and match value. + def build_queries(array_name, indices, value) + queries = [] + if indices.empty? + queries << "#{array_name} contains sameElement(\"#{value}\")" + queries << "#{array_name} contains ({elementFilter:[]}sameElement(\"#{value}\"))" + else + queries << "#{array_name} contains ({elementFilter:[#{indices.join(',')}]}sameElement(\"#{value}\"))" + if indices.length == 1 + queries << "#{array_name} contains ({elementFilter:#{indices[0]}}sameElement(\"#{value}\"))" + + # syntax sugar: field[index] = value + queries << "#{array_name}[#{indices[0]}]=#{add_quotes_if_string(value)}" + end + end + queries + end - # Does not work yet, string gets tokenized - #["float_array", "double_array"].each do |array_name| - # assert_element_filter(array_name, [0], [0], "1.0") - # assert_element_filter(array_name, [1], [], "1.0") - # assert_element_filter(array_name, [2], [], "1.0") - # assert_element_filter(array_name, [3], [], "1.0") - #end + def add_quotes_if_string(s) + return s if ["true", "false"].include?(s) + return s if is_number(s) + "\"#{s}\"" + end + def is_number(s) + s.match?(/\A-?\d+(\.\d+)?\z/) end - def assert_match_feature(array_name, element_filter, same_element) - # We check that two results are returned where the sameElement matches the first but not the second - query = {'yql' => "select * from sources * where true or (#{array_name} contains ({elementFilter:#{element_filter}}sameElement(#{same_element}))) order by id asc", - 'ranking' => 'array-rank-profile'} + def assert_docs(match_condition, expected_docids) + query = {'yql' => "select * from sources * where #{match_condition} order by id asc"} result = search(query) - assert_equal(2, result.hit.size) - assert_equal(result.hit[0].field["matchfeatures"]["matches(#{array_name})"], 1.0) - assert_equal(result.hit[1].field["matchfeatures"]["matches(#{array_name})"], 0.0) + assert_docs_result(expected_docids, result) + end + + def assert_docs_result(expected_docids, result) + assert_hitcount(result, expected_docids.length) + for i in 0...expected_docids.length do + assert_field_value(result, "documentid", "id:arrays:arrays::#{expected_docids[i]}", i) + end end - def test_bool_array_rank_feature - set_description('Test a rank-feature when using elementFilter annotation with sameElement for array of bools.') + def post_json_select(query_body) + json = { "select" => { "where" => query_body } } + json["streaming.selection"] = "true" if is_streaming + json["sorting"] = "id" + json["timeout"] = 5 + vespa.container.values.first.post_search( + "/search/", json.to_json, 0, {'Content-Type' => 'application/json'}) + end + + + ###################################################################################################################### + # Ranking test + ###################################################################################################################### + + def test_ranking + set_description('Test a rank-feature when using elementFilter annotation with sameElement for array of various data types.') deploy_app(SearchApp.new.sd(selfdir+'arrays.sd')) start - feed_docs({"bool_array" => [[true, true, true], [true, false, false]]}) + bool_arrays = [[true, true, true], [true, false, false]] + string_arrays = [["foo", "foo", "foo"], ["foo", "bar", "bar"]] + struct_arrays = [[{ "first_name" => "foo", "year_of_birth" => 1, "alive" => true }, + { "first_name" => "foo", "year_of_birth" => 1, "alive" => true }, + { "first_name" => "foo", "year_of_birth" => 1, "alive" => true }], + [{ "first_name" => "foo", "year_of_birth" => 1, "alive" => true }, + { "first_name" => "bar", "year_of_birth" => 2, "alive" => false }, + { "first_name" => "bar", "year_of_birth" => 2, "alive" => false }]] + int_arrays = [[1, 1, 1], [1, 2, 2]] + float_arrays = [[1.0, 1.0, 1.0], [1.0, 2.0, 2.0]] + + feed_docs({"bool_array" => bool_arrays, "string_array" => string_arrays, "struct_array" => struct_arrays, + "byte_array" => int_arrays, "int_array" => int_arrays, "long_array" => int_arrays, + "float_array" => float_arrays, "double_array" => float_arrays}) + assert_ranking_bool_array + assert_ranking_string_array + assert_ranking_struct_array + assert_ranking_integer_arrays + # Float matching is not possible, string gets tokenized + end + def assert_ranking_bool_array ["[1]","[1,2]"].each do |element_filter| # "true" matches the first document but not the second assert_match_feature("bool_array", element_filter, "\"true\"") end end - def test_string_array_rank_feature - set_description('Test a rank-feature when using elementFilter annotation with sameElement for array of strings.') - deploy_app(SearchApp.new.sd(selfdir+'arrays.sd')) - start - - feed_docs({"string_array" => [["foo", "foo", "foo"], ["foo", "bar", "bar"]]}) - + def assert_ranking_string_array ["[1]","[1,2]"].each do |element_filter| # "foo" matches the first document but not the second assert_match_feature("string_array", element_filter, "\"foo\"") end end - def test_numerical_arrays_rank_feature - set_description('Test a rank-feature when using elementFilter annotation with sameElement for arrays of numbers.') - deploy_app(SearchApp.new.sd(selfdir+'arrays.sd')) - start - - # Not testing float arrays yet - int_arrays = [[1, 1, 1], [1, 2, 2]] - feed_docs({"byte_array" => int_arrays, "int_array" => int_arrays, "long_array" => int_arrays}) - + def assert_ranking_integer_arrays ["byte_array", "int_array", "long_array"].each do |array_name| ["[1]","[1,2]"].each do |element_filter| # "1" matches the first document but not the second @@ -269,20 +271,7 @@ def test_numerical_arrays_rank_feature end end - def test_struct_array_rank_feature - set_description('Test a rank-feature when using elementFilter annotation with sameElement for array of struct.') - deploy_app(SearchApp.new.sd(selfdir+'arrays.sd')) - start - - first_array = [{ "first_name" => "foo", "year_of_birth" => 1, "alive" => true }, - { "first_name" => "foo", "year_of_birth" => 1, "alive" => true }, - { "first_name" => "foo", "year_of_birth" => 1, "alive" => true }] - second_array = [{ "first_name" => "foo", "year_of_birth" => 1, "alive" => true }, - { "first_name" => "bar", "year_of_birth" => 2, "alive" => false }, - { "first_name" => "bar", "year_of_birth" => 2, "alive" => false }] - - feed_docs({"struct_array" => [first_array, second_array]}) - + def assert_ranking_struct_array ["[1]","[1,2]"].each do |element_filter| # "alive contains "true"" matches the first document but not the second assert_match_feature("struct_array", element_filter, "alive contains \"true\"") @@ -294,4 +283,15 @@ def test_struct_array_rank_feature assert_match_feature("struct_array", element_filter, "year_of_birth contains \"1\"") end end + + def assert_match_feature(array_name, element_filter, same_element) + # We check that two results are returned where the sameElement matches the first but not the second + query = {'yql' => "select * from sources * where true or (#{array_name} contains ({elementFilter:#{element_filter}}sameElement(#{same_element}))) order by id asc", + 'ranking' => 'array-rank-profile'} + puts "Query: #{query}" + result = search(query) + assert_equal(2, result.hit.size) + assert_equal(result.hit[0].field["matchfeatures"]["matches(#{array_name})"], 1.0) + assert_equal(result.hit[1].field["matchfeatures"]["matches(#{array_name})"], 0.0) + end end From 542de950b914184dbe2c14450c52e4729df8f1c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6ker?= Date: Fri, 13 Mar 2026 05:32:09 +0000 Subject: [PATCH 2/4] Refactor test further --- .../element_filter_annotation.rb | 114 +++++++++--------- 1 file changed, 59 insertions(+), 55 deletions(-) diff --git a/tests/search/same_element_operator/element_filter_annotation.rb b/tests/search/same_element_operator/element_filter_annotation.rb index 46409160f..0fb6f0bd5 100644 --- a/tests/search/same_element_operator/element_filter_annotation.rb +++ b/tests/search/same_element_operator/element_filter_annotation.rb @@ -73,82 +73,86 @@ def test_matching end def assert_matching_bool_array - # [array, indices, expected_docids, value] + # [indices, value, expected_docids] [ - ["bool_array", [0], [0, 2], "true"], - ["bool_array", [1], [0, 3], "true"], - ["bool_array", [2], [1], "true"], - ["bool_array", [3], [], "true"], - ["bool_array", [0, 1], [0, 2, 3], "true"], - ["bool_array", [0, 1, 2], [0, 1, 2, 3], "true"], - ["bool_array", [0, 1, 2, 3], [0, 1, 2, 3], "true"], - ["bool_array", [1, 2, 3], [0, 1, 3], "true"], - ["bool_array", [2, 3], [1], "true"], - ["bool_array", [0], [1, 3, 4], "false"], - ["bool_array", [1], [1, 2, 4], "false"], - ["bool_array", [2], [0, 2, 3, 4], "false"], - ["bool_array", [3], [], "false"], - ["bool_array", [0, 1, 2, 3], [0, 1, 2, 3, 4], "false"], + [[0], "true", [0, 2] ], + [[1], "true", [0, 3] ], + [[2], "true", [1] ], + [[3], "true", [] ], + [[0, 1], "true", [0, 2, 3] ], + [[0, 1, 2], "true", [0, 1, 2, 3] ], + [[0, 1, 2, 3], "true", [0, 1, 2, 3] ], + [[1, 2, 3], "true", [0, 1, 3] ], + [[2, 3], "true", [1] ], + [[0], "false", [1, 3, 4] ], + [[1], "false", [1, 2, 4] ], + [[2], "false", [0, 2, 3, 4] ], + [[3], "false", [] ], + [[0, 1, 2, 3], "false", [0, 1, 2, 3, 4]], # Wrong order and duplicated elements - ["bool_array", [0, 0, 0, 0], [0, 2], "true"], - ["bool_array", [25, 25, 25, 0], [0, 2], "true"], - ].each do |array_name, indices, expected_docids, value| - assert_element_filter(array_name, indices, expected_docids, value) + [[0, 0, 0, 0], "true", [0, 2] ], + [[25, 25, 25, 0], "true", [0, 2] ], + ].each do |indices, value, expected_docids| + assert_element_filter("bool_array", indices, value, expected_docids) end end def assert_matching_string_array - # [array, indices, expected_docids, value] + # [indices, value, expected_docids] [ - ["string_array", [], [0, 4], "baz"], - ["string_array", [0], [4], "baz"], - ["string_array", [1], [4], "baz"], - ["string_array", [2], [0, 4], "baz"], - ["string_array", [3], [], "baz"], - ["string_array", [0, 1], [4], "baz"], - ["string_array", [0, 1, 2], [0, 4], "baz"], - ["string_array", [0, 1, 2, 3], [0, 4], "baz"], - ["string_array", [1, 2, 3], [0, 4], "baz"], - ["string_array", [2, 3], [0, 4], "baz"], + [[], "baz", [0, 4]], + [[0], "baz", [4] ], + [[1], "baz", [4] ], + [[2], "baz", [0, 4]], + [[3], "baz", [] ], + [[0, 1], "baz", [4] ], + [[0, 1, 2], "baz", [0, 4]], + [[0, 1, 2, 3], "baz", [0, 4]], + [[1, 2, 3], "baz", [0, 4]], + [[2, 3], "baz", [0, 4]], # Wrong order and duplicated elements - ["string_array", [0, 0, 0, 0], [4], "baz"], - ["string_array", [25, 25, 25, 0], [4], "baz"], - ].each do |array_name, indices, expected_docids, value| - assert_element_filter(array_name, indices, expected_docids, value) + [[0, 0, 0, 0], "baz", [4] ], + [[25, 25, 25, 0], "baz", [4] ], + ].each do |indices, value, expected_docids| + assert_element_filter("string_array", indices, value, expected_docids) end end def assert_matching_integer_arrays - # [indices, expected_docids, value] + # [indices, value, expected_docids] test_data = [ - [[], [2, 3, 4], "9"], - [[0], [0], "1"], - [[1], [], "1"], - [[2], [], "1"], - [[3], [], "1"], - [[0, 1, 2, 3], [0], "1"], - [[0], [3, 4], "9"], - [[1], [4], "9"], - [[2], [2, 4], "9"], - [[3], [], "9"], - [[0, 1], [3, 4], "9"], - [[0, 1, 2], [2, 3, 4], "9"], - [[0, 1, 2, 3], [2, 3, 4], "9"], - [[1, 2, 3], [2, 4], "9"], - [[2, 3], [2, 4], "9"], + [[], "9", [2, 3, 4]], + [[0], "1", [0] ], + [[1], "1", [] ], + [[2], "1", [] ], + [[3], "1", [] ], + [[0, 1, 2, 3], "1", [0] ], + [[0], "9", [3, 4] ], + [[1], "9", [4] ], + [[2], "9", [2, 4] ], + [[3], "9", [] ], + [[0, 1], "9", [3, 4] ], + [[0, 1, 2], "9", [2, 3, 4]], + [[0, 1, 2, 3], "9", [2, 3, 4]], + [[1, 2, 3], "9", [2, 4] ], + [[2, 3], "9", [2, 4] ], # Wrong order and duplicated elements - [[25, 42, 50000, 0, 0, 0, 0], [3, 4], "9"], - [[3, 2, 3, 2, 1, 0], [2, 3, 4], "9"], + [[25, 42, 50000, 0, 0, 0, 0], "9", [3, 4] ], + [[3, 2, 3, 2, 1, 0], "9", [2, 3, 4]], ] ["byte_array", "int_array", "long_array"].each do |array_name| - test_data.each do |indices, expected_docids, value| - assert_element_filter(array_name, indices, expected_docids, value) + test_data.each do |indices, value, expected_docids| + assert_element_filter(array_name, indices, value, expected_docids) end end end - def assert_element_filter(array_name, indices, expected_docids, value) + # Gets the name of an array, the indices to use for the elementFilter annotation, the value to check for, + # and the expected docids + def assert_element_filter(array_name, indices, value, expected_docids) + # We have to check that the query "array_name[indices] = value" yields exactly the expected_docids + # We are going to build different queries that express this (YQL with elementFilter annotation, YQL with shorthand form, select query) build_queries(array_name, indices, value).each do |query| assert_docs(query, expected_docids) end From c9f02a2b307de7828a39b5d0519742640ee20002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6ker?= Date: Fri, 13 Mar 2026 05:56:50 +0000 Subject: [PATCH 3/4] Refactor test even more --- .../element_filter_annotation.rb | 80 +++++++++---------- 1 file changed, 36 insertions(+), 44 deletions(-) diff --git a/tests/search/same_element_operator/element_filter_annotation.rb b/tests/search/same_element_operator/element_filter_annotation.rb index 0fb6f0bd5..01d8b29dc 100644 --- a/tests/search/same_element_operator/element_filter_annotation.rb +++ b/tests/search/same_element_operator/element_filter_annotation.rb @@ -152,41 +152,42 @@ def assert_matching_integer_arrays # and the expected docids def assert_element_filter(array_name, indices, value, expected_docids) # We have to check that the query "array_name[indices] = value" yields exactly the expected_docids - # We are going to build different queries that express this (YQL with elementFilter annotation, YQL with shorthand form, select query) - build_queries(array_name, indices, value).each do |query| - assert_docs(query, expected_docids) - end - if indices.length == 1 - query_body = { "equals" => { "field" => array_name, "index" => indices[0], "value" => to_native_value(value) } } - result = post_json_select(query_body) - assert_docs_result(expected_docids, result) - end - end - - def to_native_value(s) - return true if s == "true" - return false if s == "false" - return s.to_i if is_number(s) - s - end + # We are going to build different queries that express this (YQL, YQL with syntactic sugar, JSON select query) + # They all should yield the same result - # Returns all query variants that should produce the same result for a given - # array field, element filter indices, and match value. - def build_queries(array_name, indices, value) - queries = [] + # Build YQL queries (or rather the match conditions) + yql = [] if indices.empty? - queries << "#{array_name} contains sameElement(\"#{value}\")" - queries << "#{array_name} contains ({elementFilter:[]}sameElement(\"#{value}\"))" + yql << "#{array_name} contains sameElement(\"#{value}\")" + yql << "#{array_name} contains ({elementFilter:[]}sameElement(\"#{value}\"))" else - queries << "#{array_name} contains ({elementFilter:[#{indices.join(',')}]}sameElement(\"#{value}\"))" + yql << "#{array_name} contains ({elementFilter:[#{indices.join(',')}]}sameElement(\"#{value}\"))" if indices.length == 1 - queries << "#{array_name} contains ({elementFilter:#{indices[0]}}sameElement(\"#{value}\"))" + yql << "#{array_name} contains ({elementFilter:#{indices[0]}}sameElement(\"#{value}\"))" # syntax sugar: field[index] = value - queries << "#{array_name}[#{indices[0]}]=#{add_quotes_if_string(value)}" + yql << "#{array_name}[#{indices[0]}]=#{add_quotes_if_string(value)}" end end - queries + + # Send YQL queries + yql.each do |match_condition| + query = {'yql' => "select * from sources * where #{match_condition} order by id asc"} + puts "Sending query: #{query}" + result = search(query) + assert_docs_result(expected_docids, result) + end + + # Build and send JSON select query + if indices.length == 1 + json = { "select" => { "where" => { "equals" => { "field" => array_name, "index" => indices[0], "value" => to_native_value(value) } } }, + "sorting" => "id", + "timeout" => 5} + json["streaming.selection"] = "true" if is_streaming + puts "Sending JSON query: #{json.to_json}" + result = vespa.container.values.first.post_search("/search/", json.to_json, 0, {'Content-Type' => 'application/json'}) + assert_docs_result(expected_docids, result) + end end def add_quotes_if_string(s) @@ -195,14 +196,15 @@ def add_quotes_if_string(s) "\"#{s}\"" end - def is_number(s) - s.match?(/\A-?\d+(\.\d+)?\z/) + def to_native_value(s) + return true if s == "true" + return false if s == "false" + return s.to_i if is_number(s) + s end - def assert_docs(match_condition, expected_docids) - query = {'yql' => "select * from sources * where #{match_condition} order by id asc"} - result = search(query) - assert_docs_result(expected_docids, result) + def is_number(s) + s.match?(/\A-?\d+(\.\d+)?\z/) end def assert_docs_result(expected_docids, result) @@ -212,16 +214,6 @@ def assert_docs_result(expected_docids, result) end end - def post_json_select(query_body) - json = { "select" => { "where" => query_body } } - json["streaming.selection"] = "true" if is_streaming - json["sorting"] = "id" - json["timeout"] = 5 - vespa.container.values.first.post_search( - "/search/", json.to_json, 0, {'Content-Type' => 'application/json'}) - end - - ###################################################################################################################### # Ranking test ###################################################################################################################### @@ -292,7 +284,7 @@ def assert_match_feature(array_name, element_filter, same_element) # We check that two results are returned where the sameElement matches the first but not the second query = {'yql' => "select * from sources * where true or (#{array_name} contains ({elementFilter:#{element_filter}}sameElement(#{same_element}))) order by id asc", 'ranking' => 'array-rank-profile'} - puts "Query: #{query}" + puts "Sending query: #{query}" result = search(query) assert_equal(2, result.hit.size) assert_equal(result.hit[0].field["matchfeatures"]["matches(#{array_name})"], 1.0) From 80799b00b281cdc912b9d5a43b08d5079ac5ea19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6ker?= Date: Fri, 13 Mar 2026 06:06:07 +0000 Subject: [PATCH 4/4] Remove unused map from schema --- tests/search/same_element_operator/arrays.sd | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/search/same_element_operator/arrays.sd b/tests/search/same_element_operator/arrays.sd index 22c97583f..eab67b1a2 100644 --- a/tests/search/same_element_operator/arrays.sd +++ b/tests/search/same_element_operator/arrays.sd @@ -48,12 +48,6 @@ schema arrays { struct-field year_of_birth { indexing: attribute } struct-field alive { indexing: attribute } } - - field byte_byte_map type map { - indexing: summary - struct-field key { indexing: attribute } - struct-field value { indexing: attribute } - } } rank-profile array-rank-profile { match-features {