This is an automated email from the ASF dual-hosted git repository. vatamane pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit cc500adc1d5a44710059dabc5c54e4f48607e846 Author: Gabor Pali <[email protected]> AuthorDate: Mon Mar 27 15:20:08 2023 +0200 mango: mark fields with the `$exists` operator indexable This is required to make index selection work better with covering indexes. The `$exists` operator prescribes the presence of the given field so that if an index has the field, it shall be considered because it implies true. Without this change, it will not happen, but covering indexes can work if the index is manually picked. --- src/mango/src/mango_idx_view.erl | 94 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/src/mango/src/mango_idx_view.erl b/src/mango/src/mango_idx_view.erl index 641b8140a..e3db24fbb 100644 --- a/src/mango/src/mango_idx_view.erl +++ b/src/mango/src/mango_idx_view.erl @@ -300,6 +300,10 @@ indexable({[{<<"$gt">>, _}]}) -> true; indexable({[{<<"$gte">>, _}]}) -> true; +% This is required to improve index selection for covering indexes. +% Making `$exists` indexable should not cause problems in other cases. +indexable({[{<<"$exists">>, _}]}) -> + true; % All other operators are currently not indexable. % This is also a subtle assertion that we don't % call indexable/1 on a field name. @@ -542,6 +546,96 @@ covers(Idx, Fields) -> -ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). +indexable_fields_of(Selector) -> + indexable_fields(test_util:as_selector(Selector)). + +indexable_fields_empty_test() -> + ?assertEqual([], indexable_fields_of(#{})). + +indexable_fields_and_test() -> + Selector = #{<<"$and">> => [#{<<"field1">> => undefined, <<"field2">> => undefined}]}, + ?assertEqual([<<"field1">>, <<"field2">>], indexable_fields_of(Selector)). + +indexable_fields_or_test() -> + Selector = #{<<"$or">> => [#{<<"field1">> => undefined, <<"field2">> => undefined}]}, + ?assertEqual([], indexable_fields_of(Selector)). + +indexable_fields_nor_test() -> + Selector = #{<<"$nor">> => [#{<<"field1">> => undefined, <<"field2">> => undefined}]}, + ?assertEqual([], indexable_fields_of(Selector)). + +indexable_fields_all_test() -> + Selector = #{<<"field">> => #{<<"$all">> => []}}, + ?assertEqual([], indexable_fields_of(Selector)). + +indexable_fields_elemMatch_test() -> + Selector = #{<<"field">> => #{<<"$elemMatch">> => #{}}}, + ?assertEqual([], indexable_fields_of(Selector)). + +indexable_fields_allMatch_test() -> + Selector = #{<<"field">> => #{<<"$allMatch">> => #{}}}, + ?assertEqual([], indexable_fields_of(Selector)). + +indexable_fields_keyMapMatch_test() -> + Selector = #{<<"field">> => #{<<"$keyMapMatch">> => #{}}}, + ?assertEqual([], indexable_fields_of(Selector)). + +indexable_fields_in_test() -> + Selector = #{<<"field">> => #{<<"$in">> => []}}, + ?assertEqual([], indexable_fields_of(Selector)). + +indexable_fields_nin_test() -> + Selector = #{<<"field">> => #{<<"$nin">> => []}}, + ?assertEqual([], indexable_fields_of(Selector)). + +indexable_fields_not_test() -> + Selector = #{<<"field">> => #{<<"$not">> => #{}}}, + ?assertEqual([], indexable_fields_of(Selector)). + +indexable_fields_lt_test() -> + Selector = #{<<"field">> => #{<<"$lt">> => undefined}}, + ?assertEqual([<<"field">>], indexable_fields_of(Selector)). + +indexable_fields_lte_test() -> + Selector = #{<<"field">> => #{<<"$lte">> => undefined}}, + ?assertEqual([<<"field">>], indexable_fields_of(Selector)). + +indexable_fields_eq_test() -> + Selector = #{<<"field">> => #{<<"$eq">> => undefined}}, + ?assertEqual([<<"field">>], indexable_fields_of(Selector)). + +indexable_fields_ne_test() -> + Selector = #{<<"field">> => #{<<"$ne">> => undefined}}, + ?assertEqual([], indexable_fields_of(Selector)). + +indexable_fields_gte_test() -> + Selector = #{<<"field">> => #{<<"$gte">> => undefined}}, + ?assertEqual([<<"field">>], indexable_fields_of(Selector)). + +indexable_fields_gt_test() -> + Selector = #{<<"field">> => #{<<"$gt">> => undefined}}, + ?assertEqual([<<"field">>], indexable_fields_of(Selector)). + +indexable_fields_mod_test() -> + Selector = #{<<"field">> => #{<<"$mod">> => [0, 0]}}, + ?assertEqual([], indexable_fields_of(Selector)). + +indexable_fields_regex_test() -> + Selector = #{<<"field">> => #{<<"$regex">> => undefined}}, + ?assertEqual([], indexable_fields_of(Selector)). + +indexable_fields_exists_test() -> + Selector = #{<<"field">> => #{<<"$exists">> => true}}, + ?assertEqual([<<"field">>], indexable_fields_of(Selector)). + +indexable_fields_type_test() -> + Selector = #{<<"field">> => #{<<"$type">> => undefined}}, + ?assertEqual([], indexable_fields_of(Selector)). + +indexable_fields_size_test() -> + Selector = #{<<"field">> => #{<<"$size">> => 0}}, + ?assertEqual([], indexable_fields_of(Selector)). + covers_all_fields_test() -> ?assertNot(covers(undefined, all_fields)).
