You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ro...@apache.org on 2015/02/03 16:13:48 UTC

[41/50] [abbrv] couchdb-mango git commit: Implement the use_index query parameter

Implement the use_index query parameter

This adds the ability for users to specify a specific index to use when
responding to a query. There are a few places where its helpful to force
the index selection to a specific index. For instance choosing a more
sparse single column index over an available multi-column index.

BugzId: 33294


Project: http://git-wip-us.apache.org/repos/asf/couchdb-mango/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-mango/commit/1b0426aa
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-mango/tree/1b0426aa
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-mango/diff/1b0426aa

Branch: refs/heads/master
Commit: 1b0426aa2839f34d747e329ffb8bbaee1c42aaa8
Parents: 812cf6b
Author: Paul J. Davis <pa...@gmail.com>
Authored: Fri Jan 9 15:32:40 2015 -0600
Committer: Paul J. Davis <pa...@gmail.com>
Committed: Fri Jan 16 13:32:50 2015 -0600

----------------------------------------------------------------------
 src/mango_cursor.erl            | 35 ++++++++++++++++++++++++++++++++++-
 src/mango_opts.erl              | 33 +++++++++++++++++++++++++++++++++
 test/05-index-selection-test.py | 34 ++++++++++++++++++++++++++++++++++
 test/mango.py                   |  3 ++-
 4 files changed, 103 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-mango/blob/1b0426aa/src/mango_cursor.erl
----------------------------------------------------------------------
diff --git a/src/mango_cursor.erl b/src/mango_cursor.erl
index d4d5523..72ee8bb 100644
--- a/src/mango_cursor.erl
+++ b/src/mango_cursor.erl
@@ -36,7 +36,12 @@ create(Db, Selector0, Opts) ->
         ?MANGO_ERROR({no_usable_index, no_indexes_defined})
     end,
 
-    SortIndexes = mango_idx:for_sort(ExistingIndexes, Opts),
+    FilteredIndexes = maybe_filter_indexes(ExistingIndexes, Opts),
+    if FilteredIndexes /= [] -> ok; true ->
+        ?MANGO_ERROR({no_usable_index, no_index_matching_name})
+    end,
+
+    SortIndexes = mango_idx:for_sort(FilteredIndexes, Opts),
     if SortIndexes /= [] -> ok; true ->
         ?MANGO_ERROR({no_usable_index, missing_sort_index})
     end,
@@ -77,6 +82,34 @@ execute(#cursor{index=Idx}=Cursor, UserFun, UserAcc) ->
     Mod:execute(Cursor, UserFun, UserAcc).
 
 
+maybe_filter_indexes(Indexes, Opts) ->
+    case lists:keyfind(use_index, 1, Opts) of
+        {use_index, []} ->
+            Indexes;
+        {use_index, [DesignId]} ->
+            filter_indexes(Indexes, DesignId);
+        {use_index, [DesignId, ViewName]} ->
+            filter_indexes(Indexes, DesignId, ViewName)
+    end.
+
+
+filter_indexes(Indexes, DesignId0) ->
+    DesignId = case DesignId0 of
+        <<"_design/", _/binary>> ->
+            DesignId0;
+        Else ->
+            <<"_design/", Else/binary>>
+    end,
+    FiltFun = fun(I) -> mango_idx:ddoc(I) == DesignId end,
+    lists:filter(FiltFun, Indexes).
+
+
+filter_indexes(Indexes0, DesignId, ViewName) ->
+    Indexes = filter_indexes(Indexes0, DesignId),
+    FiltFun = fun(I) -> mango_idx:name(I) == ViewName end,
+    lists:filter(FiltFun, Indexes).
+
+
 create_cursor(Db, Indexes, Selector, Opts) ->
     [{CursorMod, CursorModIndexes} | _] = group_indexes_by_type(Indexes),
     CursorMod:create(Db, CursorModIndexes, Selector, Opts).

http://git-wip-us.apache.org/repos/asf/couchdb-mango/blob/1b0426aa/src/mango_opts.erl
----------------------------------------------------------------------
diff --git a/src/mango_opts.erl b/src/mango_opts.erl
index 43c2f31..e15a446 100644
--- a/src/mango_opts.erl
+++ b/src/mango_opts.erl
@@ -28,6 +28,7 @@
 
     validate_idx_name/1,
     validate_selector/1,
+    validate_use_index/1,
     validate_sort/1,
     validate_fields/1
 ]).
@@ -75,6 +76,12 @@ validate_find({Props}) ->
             {tag, selector},
             {validator, fun validate_selector/1}
         ]},
+        {<<"use_index">>, [
+            {tag, use_index},
+            {optional, true},
+            {default, []},
+            {validator, fun validate_use_index/1}
+        ]},
         {<<"limit">>, [
             {tag, limit},
             {optional, true},
@@ -178,6 +185,32 @@ validate_selector(Else) ->
     ?MANGO_ERROR({invalid_selector_json, Else}).
 
 
+validate_use_index(IndexName) when is_binary(IndexName) ->
+    case binary:split(IndexName, <<"/">>) of
+        [DesignId] ->
+            {ok, [DesignId]};
+        [<<"_design">>, DesignId] ->
+            {ok, [DesignId]};
+        [DesignId, ViewName] ->
+            {ok, [DesignId, ViewName]};
+        [<<"_design">>, DesignId, ViewName] ->
+            {ok, [DesignId, ViewName]};
+        _ ->
+            ?MANGO_ERROR({invalid_index_name, IndexName})
+    end;
+validate_use_index(null) ->
+    {ok, []};
+validate_use_index([]) ->
+    {ok, []};
+validate_use_index([DesignId]) when is_binary(DesignId) ->
+    {ok, [DesignId]};
+validate_use_index([DesignId, ViewName])
+        when is_binary(DesignId), is_binary(ViewName) ->
+    {ok, [DesignId, ViewName]};
+validate_use_index(Else) ->
+    ?MANGO_ERROR({invalid_index_name, Else}).
+
+
 validate_sort(Value) ->
     mango_sort:new(Value).
 

http://git-wip-us.apache.org/repos/asf/couchdb-mango/blob/1b0426aa/test/05-index-selection-test.py
----------------------------------------------------------------------
diff --git a/test/05-index-selection-test.py b/test/05-index-selection-test.py
new file mode 100644
index 0000000..5aa86c6
--- /dev/null
+++ b/test/05-index-selection-test.py
@@ -0,0 +1,34 @@
+
+import mango
+import user_docs
+
+
+class IndexSelectionTests(mango.UserDocsTests):
+
+    def test_basic(self):
+        resp = self.db.find({"name.last": "A last name"}, explain=True)
+        assert resp["index"]["type"] == "json"
+
+    def test_with_and(self):
+        resp = self.db.find({
+                "name.first": "Stephanie",
+                "name.last": "This doesn't have to match anything."
+            }, explain=True)
+        assert resp["index"]["type"] == "json"
+
+    def test_use_most_columns(self):
+        # ddoc id for the age index
+        ddocid = "_design/ad3d537c03cd7c6a43cf8dff66ef70ea54c2b40f"
+        resp = self.db.find({
+                "name.first": "Stephanie",
+                "name.last": "Something or other",
+                "age": {"$gt": 1}
+            }, explain=True)
+        assert resp["index"]["ddoc"] != "_design/" + ddocid
+
+        resp = self.db.find({
+                "name.first": "Stephanie",
+                "name.last": "Something or other",
+                "age": {"$gt": 1}
+            }, use_index=ddocid, explain=True)
+        assert resp["index"]["ddoc"] == ddocid

http://git-wip-us.apache.org/repos/asf/couchdb-mango/blob/1b0426aa/test/mango.py
----------------------------------------------------------------------
diff --git a/test/mango.py b/test/mango.py
index fac4e7e..5b022b8 100644
--- a/test/mango.py
+++ b/test/mango.py
@@ -107,9 +107,10 @@ class Database(object):
         r.raise_for_status()
 
     def find(self, selector, limit=25, skip=0, sort=None, fields=None,
-                r=1, conflicts=False, explain=False):
+                r=1, conflicts=False, explain=False, use_index=None):
         body = {
             "selector": selector,
+            "use_index": use_index,
             "limit": limit,
             "skip": skip,
             "r": r,