Commits

Anonymous committed efcaeb8

very basic Riak Search usage

latest version of each article is tossed to Search, and requests for
pages that don't exist ask Search to look for pages containing the
words of the page title requested

Comments (0)

Files changed (5)

apps/wriaki/src/wiki_resource.erl

     to_html(RD, ACtx).
 
 render_404(RD, Ctx) ->
+    Search = mochiweb_util:unquote(base64url:decode_to_string(search_path(RD))),
+    Results = search(Ctx#ctx.client, Search),
     {ok, C} = error_404_dtl:render([{req, wrq_dtl_helper:new(RD)},
-                                    {search, mochiweb_util:unquote(base64url:decode_to_string(search_path(RD)))}]),
+                                    {search, Search},
+                                    {results, Results}]),
     {C, RD, Ctx}.
+
+-define(SEARCH_FUN,
+        iolist_to_binary(
+          [<<"function(v) {\n">>,
+           <<"return [v.key];\n">>,
+           <<"}">>])).
+
+search(Client, RawSearch) ->
+    case wriaki:search_enabled() of
+        true ->
+            Search = sanitize_search(RawSearch),
+            {ok, RawResults} =
+                wrc:mapred(Client,
+                           {modfun, riak_search, mapred_search,
+                            [<<"article">>,
+                             iolist_to_binary([<<"text:">>, Search])]},
+                           [{map, {jsanon, ?SEARCH_FUN}, <<>>, true}]),
+            case RawResults of
+                [{0, RawKeys}] ->
+                    [ [{url, base64url:decode(R)},
+                       {title, mochiweb_util:unquote(base64url:decode(R))}]
+                      || R <- RawKeys ];
+                _ ->
+                    []
+            end;
+        false ->
+            []
+    end.
+
+sanitize_search(RawSearch) ->
+    [ whitespace_search_operator(C) || C <- RawSearch ].
+
+whitespace_search_operator(C) ->
+    case is_search_operator(C) of
+        true -> 32; % space
+        false -> C
+    end.
+
+-define(SEARCH_OPERATORS,
+        [
+         $:,
+         $(,
+           $),
+         ${,
+           $},
+         $[,
+           $],
+         $+,
+         $-,
+         $!,
+         $&,
+         $|,
+         $^,
+         $~,
+         $*,
+         $?,
+         34  % double quote "
+        ]).
+
+is_search_operator(C) ->
+    lists:member(C, ?SEARCH_OPERATORS).

apps/wriaki/src/wriaki.erl

 -module(wriaki).
 
 -export([set_bucket_props/0,
+         search_enabled/0,
          get_app_env/2]).
 
 -include_lib("wriaki.hrl").
 
 set_bucket_props() ->
     {ok, Client} = wrc:connect(),
-    ok = wrc:set_bucket(Client, ?B_ARTICLE, [{allow_mult, true}]),
+    ok = wrc:set_bucket(Client, ?B_ARTICLE,
+                        [{allow_mult, true}|search_hook()]),
     ok = wrc:set_bucket(Client, ?B_HISTORY, [{allow_mult, true}]).
 
+search_hook() ->
+    case search_enabled() of
+        true ->
+            [{precommit, [{struct,[{<<"mod">>,<<"riak_search_kv_hook">>},
+                                   {<<"fun">>,<<"precommit">>}]}]}];
+        _ ->
+            []
+    end.
+
+search_enabled() ->
+    get_app_env(search_enabled, false) == true.
+
 get_app_env(Env, Default) ->
     case application:get_env(wriaki, Env) of
         {ok, Val} -> Val;

apps/wriaki/templates/base.dtl

           <span class="wikiletter">i</span>
         </a>
         &nbsp;&nbsp;
-        <input id="searchtext" value="{% if search %}{{ search }}{% endif %}" />
+        <input id="searchtext" value="{% if search %}{{ search|escape }}{% endif %}" />
         <button id="searchbutton">go</button>
       </div>
       <div id="welcome">

apps/wriaki/templates/error_404.dtl

   <div class="notfound">
     <h2>No page was found for &quot;{{ search|escape }}&quot;</h2>
     <p>Would you like to <a href="/wiki/{{ search|escape }}?edit">create it</a>?</p>
+    {% if results %}
+    <h2>Perhaps you were looking for one of these pages?</h2>
+    <ul>
+      {% for result in results %}
+      <li><a href="/wiki/{{result.url}}">{{result.title|escape}}</li>
+      {% endfor %}
+    </ul>
+    {% endif%}
   </div>
 {% endblock %}

rel/overlay/etc/app.config

            {riak, {pb, {"127.0.0.1", 8087}}},
 %           {riak, {http, {"127.0.0.1", 8098, "riak"}}},
 
+           %% Search functionality
+%           {search_enabled, true},
+
            %% Web interface settings
            %% web_ip: what IP to listen on (0.0.0.0 = listen on all)
            {web_ip, "0.0.0.0"},