This commit is contained in:
byte[] 2019-08-21 21:07:58 -04:00
parent aef0e7f7d5
commit 108377462e
3 changed files with 60 additions and 38 deletions

View file

@ -8,6 +8,7 @@ defmodule Philomena.Search.Lexer do
cond do
is_float(float_val) ->
float_val
is_integer(int_val) ->
int_val
end
@ -44,7 +45,7 @@ defmodule Philomena.Search.Lexer do
quot = string("\"")
quoted_term =
quoted_term =
ignore(quot)
|> choice([
ignore(string("\\")) |> string("\""),
@ -57,47 +58,51 @@ defmodule Philomena.Search.Lexer do
|> reduce({List, :to_string, []})
|> unwrap_and_tag(:term)
stop_words = choice([
string("\\") |> eos(),
string(","),
concat(space, l_and),
concat(space, l_or),
concat(space, l_not),
rparen,
fuzz,
boost
])
stop_words =
choice([
string("\\") |> eos(),
string(","),
concat(space, l_and),
concat(space, l_or),
concat(space, l_not),
rparen,
fuzz,
boost
])
defcombinatorp :simple_term,
defcombinatorp(
:simple_term,
lookahead_not(stop_words)
|> choice([
string("\\") |> utf8_char([]),
string("(") |> parsec(:simple_term) |> string(")"),
utf8_char([]),
utf8_char([])
])
|> times(min: 1)
)
unquoted_term =
parsec(:simple_term)
|> reduce({List, :to_string, []})
|> unwrap_and_tag(:term)
outer = choice([
l_and,
l_or,
l_not,
lparen,
rparen,
boost,
fuzz,
space,
quoted_term,
unquoted_term
])
outer =
choice([
l_and,
l_or,
l_not,
lparen,
rparen,
boost,
fuzz,
space,
quoted_term,
unquoted_term
])
search =
times(outer, min: 1)
|> eos()
defparsec :search, search
end
defparsec(:search, search)
end

View file

@ -1,13 +1,12 @@
defmodule Philomena.Search.Parser do
alias Philomena.Search.Lexer
def parse(ctx, tokens) do
{tree, [eof: "$"]} = search_top(ctx, tokens)
{tree, []} = search_top(ctx, tokens)
{:ok, tree}
rescue
e in ArgumentError ->
{:error, e.message}
_ ->
{:error, "Parsing error."}
end
@ -20,11 +19,13 @@ defmodule Philomena.Search.Parser do
#
# Boolean OR
#
defp search_or(ctx, tokens) do
case search_and(ctx, tokens) do
{left, [{:or, _} | r_tokens]} ->
{right, rest} = search_top(ctx, r_tokens)
{%{bool: %{should: [left, right]}}, rest}
{child, rest} ->
{child, rest}
end
@ -33,11 +34,13 @@ defmodule Philomena.Search.Parser do
#
# Boolean AND
#
defp search_and(ctx, tokens) do
case search_boost(ctx, tokens) do
{left, [{:and, _} | r_tokens]} ->
{right, rest} = search_top(ctx, r_tokens)
{%{bool: %{must: [left, right]}}, rest}
{child, rest} ->
{child, rest}
end
@ -46,10 +49,12 @@ defmodule Philomena.Search.Parser do
#
# Subquery score boosting
#
defp search_boost(ctx, tokens) do
case search_not(ctx, tokens) do
{child, [{:boost, _}, {:float, value} | r_tokens]} ->
{%{function_score: %{query: child, boost_factor: value}}, r_tokens}
{child, rest} ->
{child, rest}
end
@ -58,40 +63,52 @@ defmodule Philomena.Search.Parser do
#
# Boolean NOT
#
defp search_not(ctx, [{:not, _} | r_tokens]) do
{child, rest} = search_top(ctx, r_tokens)
{%{bool: %{must_not: child}}, rest}
end
defp search_not(ctx, tokens), do: search_group(ctx, tokens)
#
# Logical grouping
#
defp search_group(ctx, [{:lparen, _} | rest]) do
case search_top(ctx, rest) do
{child, [{:rparen, _} | r_tokens]} ->
{child, r_tokens}
_ ->
raise ArgumentError, "Imbalanced parentheses."
end
end
defp search_group(_ctx, [{:rparen, _} | _rest]), do: raise ArgumentError, "Imbalanced parentheses."
defp search_group(_ctx, [{:rparen, _} | _rest]),
do: raise(ArgumentError, "Imbalanced parentheses.")
defp search_group(ctx, tokens), do: search_fuzz(ctx, tokens)
#
# Term fuzzing
#
defp search_fuzz(ctx, tokens) do
nil
search_term(ctx, tokens)
end
#
# Search terms
#
defp search_term(ctx, [{:term, t} | rest]) do
{TermParser.parse(ctx, t), rest}
defp search_term(_ctx, [{:term, _t} | rest]) do
{[], rest}
end
defp search_term(_ctx, [eof: "$"]), do: raise ArgumentError, "Expected a term, got <end of input>."
defp search_term(_ctx, [{_, text} | _rest]), do: raise ArgumentError, "Expected a term, got `#{text}'."
end
defp search_term(_ctx, []), do: raise(ArgumentError, "Expected a term, got <end of input>.")
defp search_term(_ctx, [{_, text} | _rest]),
do: raise(ArgumentError, "Expected a term, got `#{text}'.")
end

View file

@ -50,7 +50,7 @@ defmodule Philomena.MixProject do
{:pot, "~> 0.10.1"},
{:secure_compare, "~> 0.1.0"},
{:elastix, "~> 0.7.1"},
{:nimble_parsec, "~> 0.5.1"},
{:nimble_parsec, "~> 0.5.1"}
]
end