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)).
 

Reply via email to