Skip to content

Commit

Permalink
move JS code out of -defines and into .js files
Browse files Browse the repository at this point in the history
greatly improves readability

JS files are read during application startup, and storing in
the application environment under properties named after their filenames
  • Loading branch information
beerriot committed Nov 3, 2010
1 parent b9be0e0 commit 94c9058
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 69 deletions.
51 changes: 51 additions & 0 deletions apps/wriaki/priv/mapred/search_map.js
@@ -0,0 +1,51 @@
// This function is used as the map phase implementation for
// searching article text
// Each element in the result should be a structure of
// {
// key: (string), // key of the Riak object for the article
// ranges: [ (string) ], // list of matching phrases
// }
function(v, d) {
// always want the key in the result
var result = {key: v.key};

// if the object was found, and we have word position info
if (v.values && v.values[0] && d.p) {
// sort positions
d.p.sort();

// create a list of start/end position pairs that attempt
// to group "close" positions (within 5 words) together
result.ranges=[{start: d.p[0], end: d.p[0]}];
for (var i = 1; i < d.p.length; i++) {
if (result.ranges[result.ranges.length-1].end-d.p[i] < 5)
result.ranges[result.ranges.length-1].end = d.p[i];
else
result.ranges[result.ranges.length] =
{start: d.p[i], end: d.p[i]};
}

// extract the phrases from the text
var text = JSON.parse(v.values[0].data).text;
var words = text.match(/[a-z0-9\u80-\uff]*/g).filter(
function(s) { return s != ""; }).length

for (var i = 0; i < result.ranges.length; i++) {
var s = result.ranges[i].start < 5 ?
0 : result.ranges[i].start-5;
var e = result.ranges[i].end+5 > words ?
words : result.ranges[i].end+5;

// regexp is basically "match START words, then grab everything
// until WORDS-END words from the end"
var match = (new RegExp(
"(?:[a-z0-9\u80-\uff]+[^a-z0-9\u80-\uff]+){"+s+"}"+
"(.*)[^a-z0-9\u80-\uff]"+
"(?:[a-z0-9\u80-\uff]+[^a-z0-9\u80-\uff]+){"+(words-e)+"}"))
.exec(text);
result.ranges[i] = match[1];
}
}

return [result];
}
24 changes: 24 additions & 0 deletions apps/wriaki/priv/mapred/summary_map.js
@@ -0,0 +1,24 @@
// This function is used as the map phase implementation for
// extracting summary data from archives for history production
// Each element in the result should be a structure of
// {
// version: (string), // the hash version of the revision
// timestamp: (integer), // the time of the revision
// message: (string), // the commit message
// editor: (string), // the username of the editor
// }
function(v) {
var json = JSON.parse(v.values[0].data);
var summary = {
version: json.version,
timestamp: json.timestamp,
message: json.message,
};
var links = v.values[0].metadata.Links;
for(var i in links) {
if (links[i][2] == "editor") {
summary.editor = links[i][1];
}
}
return [summary];
}
7 changes: 7 additions & 0 deletions apps/wriaki/priv/mapred/time_order_reduce.js
@@ -0,0 +1,7 @@
// This function is used as the reduce phase implementation for
// ordering/paging archives in the history view (TODO)
function(v) {
return v.sort(
function(a,b) { return b[2]-a[2]; }
);
}
39 changes: 12 additions & 27 deletions apps/wriaki/src/article_history.erl
Expand Up @@ -60,37 +60,22 @@ merge_links(Obj, Acc) ->
Acc,
wobj:get_links(Obj)).

-define(TIME_ORDER,
iolist_to_binary(
[<<"function(v) {\n">>,
<<"return v.sort(\n">>,
<<"function(a,b) { return b[2]-a[2]; }\n">>,
<<"); }">>])).

-define(SUMMARY_EXTRACTION,
iolist_to_binary(
[<<"function(v) {\n">>,
<<"var json = JSON.parse(v.values[0].data);\n">>,
<<"var summary = {\n">>,
<<"version: json.version,\n">>,
<<"timestamp: json.timestamp,\n">>,
<<"message: json.message,\n">>,
<<"};\n">>,
<<"var links = v.values[0].metadata.Links;\n">>,
<<"for(var i in links) {\n">>,
<<"if (links[i][2] == \"editor\") {\n">>,
<<"summary.editor = links[i][1];\n">>,
<<"}\n">>,
<<"}\n">>,
<<"return [summary];\n">>,
<<"}">>])).

get_version_summaries(ArticleKey) ->
{ok, Client} = wrc:connect(),
{ok, [{1, Results}]} =
wrc:mapred(Client,
[{?B_HISTORY, ArticleKey}],
[{link, <<"archive">>, '_', false},
%%%{reduce, {jsanon, ?TIME_ORDER}, <<>>, false}, %TODO: paging
{map, {jsanon, ?SUMMARY_EXTRACTION}, <<>>, true}]),
%%%{reduce, {jsanon, time_order_fun()}, <<>>, false}, %TODO: paging
{map, {jsanon, summary_fun()}, <<>>, true}]),
{ok, Results}.

%% code for summary map phase is in priv/mapred/summary_map.js
summary_fun() ->
wriaki:get_app_env(summary_map,
<<"function() { return []; }">>).

%% code for time order reduce phase is in priv/mapred/time_order_reduce.js
time_order_fun() ->
wriaki:get_app_env(time_order_reduce,
<<"function(v) { return v; }">>).
48 changes: 6 additions & 42 deletions apps/wriaki/src/wiki_resource.erl
Expand Up @@ -253,47 +253,6 @@ render_404(RD, Ctx) ->
{results, Results}]),
{C, RD, Ctx}.

-define(SEARCH_FUN,
iolist_to_binary(
[<<"function(v, d) {\n">>,

%% always want the key in the result
<<"var result = {key: v.key};\n">>,

%% if the object was found, and we have word position info
<<"if (v.values && v.values[0] && d.p) {\n">>,

%% sort positions
<<"d.p.sort();\n">>,

%% create a list of start/end position pairs that attempt
%% to group "close" positions (within 5 words) together
<<"result.ranges=[{start: d.p[0], end: d.p[0]}];\n">>,
<<"for (var i = 1; i < d.p.length; i++) {\n">>,
<<"if (result.ranges[result.ranges.length-1].end-d.p[i] < 5)\n">>,
<<"result.ranges[result.ranges.length-1].end = d.p[i];\n">>,
<<"else\n">>,
<<"result.ranges[result.ranges.length] = {start: d.p[i], end: d.p[i]};\n">>,
<<"}\n">>,

%% extract the phrases from the text
<<"var text = JSON.parse(v.values[0].data).text;\n">>,
<<"var words = text.match(/[a-z0-9\u80-\uff]*/g).filter(function(s) { return s != \"\"; }).length\n">>,

<<"for (var i = 0; i < result.ranges.length; i++) {\n">>,
<<"var s = result.ranges[i].start < 5 ? 0 : result.ranges[i].start-5;\n">>,
<<"var e = result.ranges[i].end+5 > words ? words : result.ranges[i].end+5;\n">>,
%% regexp is basically "match START words, then grab everything
%% until WORDS-END words from the end"
<<"var match = (new RegExp(\"(?:[a-z0-9\u80-\uff]+[^a-z0-9\u80-\uff]+){\"+s+\"}(.*)[^a-z0-9\u80-\uff](?:[a-z0-9\u80-\uff]+[^a-z0-9\u80-\uff]+){\"+(words-e)+\"}\")).exec(text);\n">>,
<<"result.ranges[i] = match[1];\n">>,
<<"}\n">>,

<<"}\n">>, % end of if values & positions

<<"return [result];\n">>,
<<"}">>])).

search(Client, RawSearch) ->
case wriaki:search_enabled() of
true ->
Expand All @@ -302,7 +261,7 @@ search(Client, RawSearch) ->
wrc:mapred(Client,
{modfun, riak_search, mapred_search,
[<<"article">>, iolist_to_binary(Search)]},
[{map, {jsanon, ?SEARCH_FUN}, <<>>, true}]),
[{map, {jsanon, search_fun()}, <<>>, true}]),
case RawResults of
[{0, Results}] ->
[ [{title, base64url:decode(
Expand All @@ -316,6 +275,11 @@ search(Client, RawSearch) ->
[]
end.

%% code for search map phase is in priv/mapred/search_map.js
search_fun() ->
wriaki:get_app_env(search_map,
<<"function(v) { return [{key:v.key}]; }">>).

split_search(Search) ->
Tokens = string:tokens(Search, " "),
string:join([ [<<"text:">>, T] || T <- Tokens ], " OR ").
Expand Down
14 changes: 14 additions & 0 deletions apps/wriaki/src/wriaki.erl
Expand Up @@ -21,6 +21,7 @@

-export([set_bucket_props/0,
search_enabled/0,
read_mapred_js/0,
get_app_env/2]).

-include_lib("wriaki.hrl").
Expand Down Expand Up @@ -48,3 +49,16 @@ get_app_env(Env, Default) ->
{ok, Val} -> Val;
undefined -> Default
end.

%% Read each file in PRIV/mapred/<filename>.js and set its content
%% as wriaki application env <filename>
read_mapred_js() ->
Dir = filename:join(code:priv_dir(wriaki), "mapred"),
Filenames = filelib:wildcard("*.js", Dir),
lists:foreach(
fun(Name) ->
{ok, Content} = file:read_file(filename:join(Dir, Name)),
Atom = list_to_atom(hd(string:tokens(Name, "."))),
application:set_env(wriaki, Atom, Content)
end,
Filenames).
1 change: 1 addition & 0 deletions apps/wriaki/src/wriaki_sup.erl
Expand Up @@ -45,6 +45,7 @@ start_link() ->

init([]) ->
wriaki:set_bucket_props(),
wriaki:read_mapred_js(),

Ip = wriaki:get_app_env(web_ip, "0.0.0.0"),
Port = wriaki:get_app_env(web_port, 8000),
Expand Down

0 comments on commit 94c9058

Please sign in to comment.