elvanja
Recommendation for building search parser
Need to build a “natural” language search query parser, for later conversion to appropriate Elasticsearch query.
Basically need something like https://github.com/Financial-Times/n-search-parser, which can do:
- Conjunction operators:
AND,OR,NOT - Quoted phrases:
"Modesty Blase" - Grouping with parentheses:
("Modesty Blase" OR "Willie Garvin")
I’m trying to decide which approach to take, e.g.:
- GitHub - dashbitco/nimble_parsec: A simple and fast library for text-based parser combinators · GitHub
- GitHub - OvermindDL1/ex_spirit · GitHub
- GitHub - bitwalker/combine: A parser combinator library for Elixir projects · GitHub
- Leex and Yecc
As per Best way to build a parser - #3 by david_ex it would seem that Nimble Parsec is the best candidate. There is even Pegasus — pegasus v1.0.0 which could generate Nimble Parsec parsers (can’t find any boolean search PEG definitions out there though!).
But, as far as I can tell, the Leex and Yecc solution would be more concise.
Most Liked
kip
You can get quite a long way just using the Elixir lexer. Especially now that in Elixir 1.16 its lexing errors are better for user experience.
Example
iex> Code.string_to_quoted "(\"Modesty Blase\" or \"Willie Garvin\")"
{:ok, {:or, [line: 1], ["Modesty Blase", "Willie Garvin"]}}
iex> Code.string_to_quoted "a or (b and c)"
{:ok,
{:or, [line: 1],
[
{:a, [line: 1], nil},
{:and, [line: 1], [{:b, [line: 1], nil}, {:c, [line: 1], nil}]}
]}}
iex> Code.string_to_quoted "a or (b and c"
{:error,
{[opening_delimiter: :"(", line: 1, column: 14],
"missing terminator: ) (for \"(\" starting at line 1)", ""}}
You would then need a parser to ensure you have a valid expression for your query language but I think thats really quite easy compared to the lexical part given your reasonably straight forward requirements.
elvanja
Good point about silently ignoring grammar errors! Haven’t considered that one and it does make sense. E.g. given search for Modesty Blase OR Willie Garvin AND it makes sense to drop the last AND since it does not serve any purpose.
Would love to formalize requirements but unfortunately this will go the “let’s see how it works and then we’ll improve” way. Not that this is bad, just that it does not yield to formalization well ![]()
So for the time being I used a plain approach, scanning the input. See the gist link in reply above. This solution does that, ignores certain input errors (drops tailing operators, uses only the last operator if more than one are supplied, …). It does not say at which character e.g. unclosed parenthesis started, but it should be fairly simple to add that too (it is scanning so counting should not be an issue).
I do plan to try some/all of those solutions and see if I can get a more maintainable solution after all. Hope it will be possible to also ignore certain “invalid” input and have nice enough error reporting.
Thanks for the idea! ![]()
christhekeele
Based on your stated requirements
Any one of your proposed solutions should work well and require a few dozen lines to tokenize input into an AST ready to be manipulated into ES query syntax.
I would definitely formalize the yet-unstated requirements of how you need to handle parse errors before proceeding to make a choice. Many of these tools produce nice AST on valid input but are ill-suited to providing rich feedback about what went wrong, where, on invalid input.
Do you need to tell users where they are missing a parenthesis, or that something must follow a NOT before a closing paren, and how well do these libraries let you do that? Is there a strategy you can implement for silently ignoring grammar errors in part of the input but accepting the rest, and which of these libraries give you tools to do that? etc.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #javascript
- #code-sync
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








