elasticsearch_query_parser 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +27 -0
- data/README.md +196 -0
- data/lib/doc/ElasticsearchQueryParser/Grammar/Parser.html +108 -0
- data/lib/doc/ElasticsearchQueryParser/Grammar/Presenters/Operator/InvalidOperatorString.html +206 -0
- data/lib/doc/ElasticsearchQueryParser/Grammar/Presenters/Operator.html +209 -0
- data/lib/doc/ElasticsearchQueryParser/Grammar/Presenters/Query.html +208 -0
- data/lib/doc/ElasticsearchQueryParser/Grammar/Presenters/Term.html +203 -0
- data/lib/doc/ElasticsearchQueryParser/Grammar/Presenters.html +99 -0
- data/lib/doc/ElasticsearchQueryParser/Grammar/Transformer.html +108 -0
- data/lib/doc/ElasticsearchQueryParser/Grammar.html +99 -0
- data/lib/doc/ElasticsearchQueryParser/ParseFailedException.html +163 -0
- data/lib/doc/ElasticsearchQueryParser/Sentence.html +219 -0
- data/lib/doc/ElasticsearchQueryParser.html +238 -0
- data/lib/doc/created.rid +8 -0
- data/lib/doc/css/fonts.css +167 -0
- data/lib/doc/css/rdoc.css +619 -0
- data/lib/doc/fonts/Lato-Light.ttf +0 -0
- data/lib/doc/fonts/Lato-LightItalic.ttf +0 -0
- data/lib/doc/fonts/Lato-Regular.ttf +0 -0
- data/lib/doc/fonts/Lato-RegularItalic.ttf +0 -0
- data/lib/doc/fonts/SourceCodePro-Bold.ttf +0 -0
- data/lib/doc/fonts/SourceCodePro-Regular.ttf +0 -0
- data/lib/doc/images/add.png +0 -0
- data/lib/doc/images/arrow_up.png +0 -0
- data/lib/doc/images/brick.png +0 -0
- data/lib/doc/images/brick_link.png +0 -0
- data/lib/doc/images/bug.png +0 -0
- data/lib/doc/images/bullet_black.png +0 -0
- data/lib/doc/images/bullet_toggle_minus.png +0 -0
- data/lib/doc/images/bullet_toggle_plus.png +0 -0
- data/lib/doc/images/date.png +0 -0
- data/lib/doc/images/delete.png +0 -0
- data/lib/doc/images/find.png +0 -0
- data/lib/doc/images/loadingAnimation.gif +0 -0
- data/lib/doc/images/macFFBgHack.png +0 -0
- data/lib/doc/images/package.png +0 -0
- data/lib/doc/images/page_green.png +0 -0
- data/lib/doc/images/page_white_text.png +0 -0
- data/lib/doc/images/page_white_width.png +0 -0
- data/lib/doc/images/plugin.png +0 -0
- data/lib/doc/images/ruby.png +0 -0
- data/lib/doc/images/tag_blue.png +0 -0
- data/lib/doc/images/tag_green.png +0 -0
- data/lib/doc/images/transparent.png +0 -0
- data/lib/doc/images/wrench.png +0 -0
- data/lib/doc/images/wrench_orange.png +0 -0
- data/lib/doc/images/zoom.png +0 -0
- data/lib/doc/index.html +107 -0
- data/lib/doc/js/darkfish.js +84 -0
- data/lib/doc/js/navigation.js +105 -0
- data/lib/doc/js/navigation.js.gz +0 -0
- data/lib/doc/js/search.js +110 -0
- data/lib/doc/js/search_index.js +1 -0
- data/lib/doc/js/search_index.js.gz +0 -0
- data/lib/doc/js/searcher.js +229 -0
- data/lib/doc/js/searcher.js.gz +0 -0
- data/lib/doc/table_of_contents.html +175 -0
- data/lib/elasticsearch_query_parser/grammar/parser.rb +29 -0
- data/lib/elasticsearch_query_parser/grammar/presenters/operator.rb +41 -0
- data/lib/elasticsearch_query_parser/grammar/presenters/query.rb +45 -0
- data/lib/elasticsearch_query_parser/grammar/presenters/term.rb +21 -0
- data/lib/elasticsearch_query_parser/grammar/transformer.rb +37 -0
- data/lib/elasticsearch_query_parser/sentence.rb +55 -0
- data/lib/elasticsearch_query_parser.rb +52 -0
- metadata +135 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
|
|
3
|
+
<html>
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
|
|
7
|
+
<title>Table of Contents - RDoc Documentation</title>
|
|
8
|
+
|
|
9
|
+
<script type="text/javascript">
|
|
10
|
+
var rdoc_rel_prefix = "./";
|
|
11
|
+
var index_rel_prefix = "./";
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<script src="./js/navigation.js" defer></script>
|
|
15
|
+
<script src="./js/search.js" defer></script>
|
|
16
|
+
<script src="./js/search_index.js" defer></script>
|
|
17
|
+
<script src="./js/searcher.js" defer></script>
|
|
18
|
+
<script src="./js/darkfish.js" defer></script>
|
|
19
|
+
|
|
20
|
+
<link href="./css/fonts.css" rel="stylesheet">
|
|
21
|
+
<link href="./css/rdoc.css" rel="stylesheet">
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
<body id="top" class="table-of-contents">
|
|
27
|
+
<main role="main">
|
|
28
|
+
<h1 class="class">Table of Contents - RDoc Documentation</h1>
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
<h2 id="classes">Classes and Modules</h2>
|
|
34
|
+
<ul>
|
|
35
|
+
|
|
36
|
+
<li class="module">
|
|
37
|
+
<a href="ElasticsearchQueryParser.html">ElasticsearchQueryParser</a>
|
|
38
|
+
|
|
39
|
+
</li>
|
|
40
|
+
|
|
41
|
+
<li class="module">
|
|
42
|
+
<a href="ElasticsearchQueryParser/Grammar.html">ElasticsearchQueryParser::Grammar</a>
|
|
43
|
+
|
|
44
|
+
</li>
|
|
45
|
+
|
|
46
|
+
<li class="class">
|
|
47
|
+
<a href="ElasticsearchQueryParser/Grammar/Parser.html">ElasticsearchQueryParser::Grammar::Parser</a>
|
|
48
|
+
|
|
49
|
+
</li>
|
|
50
|
+
|
|
51
|
+
<li class="module">
|
|
52
|
+
<a href="ElasticsearchQueryParser/Grammar/Presenters.html">ElasticsearchQueryParser::Grammar::Presenters</a>
|
|
53
|
+
|
|
54
|
+
</li>
|
|
55
|
+
|
|
56
|
+
<li class="class">
|
|
57
|
+
<a href="ElasticsearchQueryParser/Grammar/Presenters/Operator.html">ElasticsearchQueryParser::Grammar::Presenters::Operator</a>
|
|
58
|
+
|
|
59
|
+
</li>
|
|
60
|
+
|
|
61
|
+
<li class="class">
|
|
62
|
+
<a href="ElasticsearchQueryParser/Grammar/Presenters/Operator/InvalidOperatorString.html">ElasticsearchQueryParser::Grammar::Presenters::Operator::InvalidOperatorString</a>
|
|
63
|
+
|
|
64
|
+
</li>
|
|
65
|
+
|
|
66
|
+
<li class="class">
|
|
67
|
+
<a href="ElasticsearchQueryParser/Grammar/Presenters/Query.html">ElasticsearchQueryParser::Grammar::Presenters::Query</a>
|
|
68
|
+
|
|
69
|
+
</li>
|
|
70
|
+
|
|
71
|
+
<li class="class">
|
|
72
|
+
<a href="ElasticsearchQueryParser/Grammar/Presenters/Term.html">ElasticsearchQueryParser::Grammar::Presenters::Term</a>
|
|
73
|
+
|
|
74
|
+
</li>
|
|
75
|
+
|
|
76
|
+
<li class="class">
|
|
77
|
+
<a href="ElasticsearchQueryParser/Grammar/Transformer.html">ElasticsearchQueryParser::Grammar::Transformer</a>
|
|
78
|
+
|
|
79
|
+
</li>
|
|
80
|
+
|
|
81
|
+
<li class="class">
|
|
82
|
+
<a href="ElasticsearchQueryParser/ParseFailedException.html">ElasticsearchQueryParser::ParseFailedException</a>
|
|
83
|
+
|
|
84
|
+
</li>
|
|
85
|
+
|
|
86
|
+
<li class="class">
|
|
87
|
+
<a href="ElasticsearchQueryParser/Sentence.html">ElasticsearchQueryParser::Sentence</a>
|
|
88
|
+
|
|
89
|
+
</li>
|
|
90
|
+
|
|
91
|
+
</ul>
|
|
92
|
+
|
|
93
|
+
<h2 id="methods">Methods</h2>
|
|
94
|
+
<ul>
|
|
95
|
+
|
|
96
|
+
<li class="method">
|
|
97
|
+
<a href="ElasticsearchQueryParser.html#method-c-configuration">::configuration</a>
|
|
98
|
+
—
|
|
99
|
+
<span class="container">ElasticsearchQueryParser</span>
|
|
100
|
+
|
|
101
|
+
<li class="method">
|
|
102
|
+
<a href="ElasticsearchQueryParser.html#method-c-configure">::configure</a>
|
|
103
|
+
—
|
|
104
|
+
<span class="container">ElasticsearchQueryParser</span>
|
|
105
|
+
|
|
106
|
+
<li class="method">
|
|
107
|
+
<a href="ElasticsearchQueryParser/ParseFailedException.html#method-c-new">::new</a>
|
|
108
|
+
—
|
|
109
|
+
<span class="container">ElasticsearchQueryParser::ParseFailedException</span>
|
|
110
|
+
|
|
111
|
+
<li class="method">
|
|
112
|
+
<a href="ElasticsearchQueryParser/Grammar/Presenters/Operator.html#method-c-new">::new</a>
|
|
113
|
+
—
|
|
114
|
+
<span class="container">ElasticsearchQueryParser::Grammar::Presenters::Operator</span>
|
|
115
|
+
|
|
116
|
+
<li class="method">
|
|
117
|
+
<a href="ElasticsearchQueryParser/Grammar/Presenters/Operator/InvalidOperatorString.html#method-c-new">::new</a>
|
|
118
|
+
—
|
|
119
|
+
<span class="container">ElasticsearchQueryParser::Grammar::Presenters::Operator::InvalidOperatorString</span>
|
|
120
|
+
|
|
121
|
+
<li class="method">
|
|
122
|
+
<a href="ElasticsearchQueryParser/Grammar/Presenters/Query.html#method-c-new">::new</a>
|
|
123
|
+
—
|
|
124
|
+
<span class="container">ElasticsearchQueryParser::Grammar::Presenters::Query</span>
|
|
125
|
+
|
|
126
|
+
<li class="method">
|
|
127
|
+
<a href="ElasticsearchQueryParser/Grammar/Presenters/Term.html#method-c-new">::new</a>
|
|
128
|
+
—
|
|
129
|
+
<span class="container">ElasticsearchQueryParser::Grammar::Presenters::Term</span>
|
|
130
|
+
|
|
131
|
+
<li class="method">
|
|
132
|
+
<a href="ElasticsearchQueryParser/Sentence.html#method-c-new">::new</a>
|
|
133
|
+
—
|
|
134
|
+
<span class="container">ElasticsearchQueryParser::Sentence</span>
|
|
135
|
+
|
|
136
|
+
<li class="method">
|
|
137
|
+
<a href="ElasticsearchQueryParser.html#method-c-parse_query">::parse_query</a>
|
|
138
|
+
—
|
|
139
|
+
<span class="container">ElasticsearchQueryParser</span>
|
|
140
|
+
|
|
141
|
+
<li class="method">
|
|
142
|
+
<a href="ElasticsearchQueryParser/Grammar/Presenters/Operator/InvalidOperatorString.html#method-i-message">#message</a>
|
|
143
|
+
—
|
|
144
|
+
<span class="container">ElasticsearchQueryParser::Grammar::Presenters::Operator::InvalidOperatorString</span>
|
|
145
|
+
|
|
146
|
+
<li class="method">
|
|
147
|
+
<a href="ElasticsearchQueryParser/Grammar/Presenters/Operator.html#method-i-to_elasticsearch">#to_elasticsearch</a>
|
|
148
|
+
—
|
|
149
|
+
<span class="container">ElasticsearchQueryParser::Grammar::Presenters::Operator</span>
|
|
150
|
+
|
|
151
|
+
<li class="method">
|
|
152
|
+
<a href="ElasticsearchQueryParser/Grammar/Presenters/Query.html#method-i-to_elasticsearch">#to_elasticsearch</a>
|
|
153
|
+
—
|
|
154
|
+
<span class="container">ElasticsearchQueryParser::Grammar::Presenters::Query</span>
|
|
155
|
+
|
|
156
|
+
<li class="method">
|
|
157
|
+
<a href="ElasticsearchQueryParser/Grammar/Presenters/Term.html#method-i-to_elasticsearch">#to_elasticsearch</a>
|
|
158
|
+
—
|
|
159
|
+
<span class="container">ElasticsearchQueryParser::Grammar::Presenters::Term</span>
|
|
160
|
+
|
|
161
|
+
<li class="method">
|
|
162
|
+
<a href="ElasticsearchQueryParser/Sentence.html#method-i-to_s">#to_s</a>
|
|
163
|
+
—
|
|
164
|
+
<span class="container">ElasticsearchQueryParser::Sentence</span>
|
|
165
|
+
|
|
166
|
+
</ul>
|
|
167
|
+
</main>
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
<footer id="validator-badges" role="contentinfo">
|
|
171
|
+
<p><a href="https://validator.w3.org/check/referer">Validate</a>
|
|
172
|
+
<p>Generated by <a href="https://ruby.github.io/rdoc/">RDoc</a> 6.2.0.
|
|
173
|
+
<p>Based on <a href="http://deveiate.org/projects/Darkfish-RDoc/">Darkfish</a> by <a href="http://deveiate.org">Michael Granger</a>.
|
|
174
|
+
</footer>
|
|
175
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module ElasticsearchQueryParser
|
|
2
|
+
module Grammar
|
|
3
|
+
# User query grammar description (PEG tree)
|
|
4
|
+
class Parser < ::Parslet::Parser
|
|
5
|
+
rule(:lparen) { str("(") >> space? }
|
|
6
|
+
rule(:rparen) { str(")") >> space? }
|
|
7
|
+
rule(:quotes) { str("'") }
|
|
8
|
+
rule(:space) { match("\s").repeat(1) }
|
|
9
|
+
rule(:space?) { space.maybe }
|
|
10
|
+
|
|
11
|
+
rule(:operator) {
|
|
12
|
+
(
|
|
13
|
+
str("AND") | str("and") | str("OR") | str("or") | str("NOT") | str("not")
|
|
14
|
+
).as(:operator) >> space
|
|
15
|
+
}
|
|
16
|
+
rule(:operator?) { operator.maybe }
|
|
17
|
+
|
|
18
|
+
rule(:single_term) { match("[a-zA-z]").repeat(1).as(:term) }
|
|
19
|
+
rule(:phrase_term) { quotes >> match("[^']").repeat(1).as(:term) >> quotes }
|
|
20
|
+
rule(:term) { (phrase_term | single_term) >> space? }
|
|
21
|
+
|
|
22
|
+
rule(:clause) { term >> operator >> query }
|
|
23
|
+
rule(:paren_clause) { lparen >> query >> rparen }
|
|
24
|
+
rule(:query) { (paren_clause | clause | term).repeat.as(:query) }
|
|
25
|
+
|
|
26
|
+
root(:query)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module ElasticsearchQueryParser
|
|
2
|
+
module Grammar
|
|
3
|
+
module Presenters
|
|
4
|
+
class Operator
|
|
5
|
+
class InvalidOperatorString < StandardError
|
|
6
|
+
attr_reader :string
|
|
7
|
+
private :string
|
|
8
|
+
|
|
9
|
+
def initialize(string)
|
|
10
|
+
@string = string
|
|
11
|
+
super
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def message
|
|
15
|
+
"Invalid operator: #{string}"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
attr_reader :operator
|
|
20
|
+
private :operator
|
|
21
|
+
|
|
22
|
+
def initialize(operator)
|
|
23
|
+
@operator = (operator || "OR").to_s.downcase
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_elasticsearch
|
|
27
|
+
case operator
|
|
28
|
+
when "and"
|
|
29
|
+
:must
|
|
30
|
+
when "not"
|
|
31
|
+
:must_not
|
|
32
|
+
when "or"
|
|
33
|
+
:should
|
|
34
|
+
else
|
|
35
|
+
raise InvalidOperatorString, operator
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module ElasticsearchQueryParser
|
|
2
|
+
module Grammar
|
|
3
|
+
module Presenters
|
|
4
|
+
class Query
|
|
5
|
+
attr_reader :terms, :operator, :nested_query
|
|
6
|
+
private :terms, :operator, :nested_query
|
|
7
|
+
|
|
8
|
+
def initialize(terms, operator, nested_query)
|
|
9
|
+
@terms = terms
|
|
10
|
+
@operator = operator
|
|
11
|
+
@nested_query = nested_query
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# If its `must_not` operator - just add `must_not` to root node and continue analyze nested queries
|
|
15
|
+
# Otherwise for nested query add new nested nodes
|
|
16
|
+
def to_elasticsearch(include_bool_header = true)
|
|
17
|
+
query = if operator.to_elasticsearch == :must_not
|
|
18
|
+
result = nested_query[0].to_elasticsearch(false)
|
|
19
|
+
result.merge(must_not: result.fetch(:must_not, []) + match_query(terms))
|
|
20
|
+
else
|
|
21
|
+
{ operator.to_elasticsearch => match_query(terms + nested_query) }
|
|
22
|
+
end
|
|
23
|
+
include_bool_header ? { bool: query } : query
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
# if is a term then build match query, otherwise (nested query) - just add to query as is
|
|
29
|
+
def match_query(sentence)
|
|
30
|
+
sentence.map do |expression|
|
|
31
|
+
if expression.is_a?(Term)
|
|
32
|
+
{ match: { search_field_name => expression.to_elasticsearch } }
|
|
33
|
+
else
|
|
34
|
+
expression.to_elasticsearch
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def search_field_name
|
|
40
|
+
::ElasticsearchQueryParser.configuration.elastic_field_name
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module ElasticsearchQueryParser
|
|
2
|
+
module Grammar
|
|
3
|
+
module Presenters
|
|
4
|
+
class Term
|
|
5
|
+
attr_reader :term
|
|
6
|
+
private :term
|
|
7
|
+
|
|
8
|
+
def initialize(term)
|
|
9
|
+
@term = term.to_s
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_elasticsearch
|
|
13
|
+
{
|
|
14
|
+
query: term,
|
|
15
|
+
operator: "and"
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require_relative "presenters/operator"
|
|
2
|
+
require_relative "presenters/query"
|
|
3
|
+
require_relative "presenters/term"
|
|
4
|
+
|
|
5
|
+
module ElasticsearchQueryParser
|
|
6
|
+
module Grammar
|
|
7
|
+
# Transform rules (accept PEG trees) from Parslet grammar and modify trees according to described rules
|
|
8
|
+
class Transformer < ::Parslet::Transform
|
|
9
|
+
# Base grammar atom (leaf)
|
|
10
|
+
rule(term: simple(:term)) { Presenters::Term.new(term) }
|
|
11
|
+
|
|
12
|
+
# It can be simple tree with terms only - query: [{term}, {term}, ...]
|
|
13
|
+
# Or it can be deeply nested tree with sub queries
|
|
14
|
+
rule(query: subtree(:query)) do
|
|
15
|
+
if query.all? { |element| element.is_a?(Presenters::Term) }
|
|
16
|
+
Presenters::Query.new(
|
|
17
|
+
query,
|
|
18
|
+
Presenters::Operator.new("OR"),
|
|
19
|
+
[]
|
|
20
|
+
)
|
|
21
|
+
else
|
|
22
|
+
# Retrieve nested query
|
|
23
|
+
query[0]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Nested query rule
|
|
28
|
+
rule(term: simple(:term), operator: simple(:operator), query: subtree(:query)) do
|
|
29
|
+
Presenters::Query.new(
|
|
30
|
+
[Presenters::Term.new(term)],
|
|
31
|
+
Presenters::Operator.new(operator),
|
|
32
|
+
query
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module ElasticsearchQueryParser
|
|
2
|
+
# Transform user query to `Left to Right` expression for parser usage
|
|
3
|
+
class Sentence
|
|
4
|
+
attr_reader :sentence
|
|
5
|
+
private :sentence
|
|
6
|
+
|
|
7
|
+
# Split by whitespace, but not split words in quotes
|
|
8
|
+
WORD_SPLITTER_REGEX = /(?:'(?:\\.|[^'])*'|[^' ])+/.freeze
|
|
9
|
+
|
|
10
|
+
# Initialize with user input
|
|
11
|
+
def initialize(sentence)
|
|
12
|
+
@sentence = sentence
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Return valid for parser usage user input
|
|
16
|
+
# Example:
|
|
17
|
+
# >> ElasticsearchQueryParser.new("(London AND Madrid) OR Paris").to_s
|
|
18
|
+
# => "Paris OR ( Madrid AND London )"
|
|
19
|
+
def to_s
|
|
20
|
+
left_to_right? ? sentence : revert_left_to_right
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def revert_left_to_right
|
|
26
|
+
prepared_sentence.scan(WORD_SPLITTER_REGEX).reverse.map do |word|
|
|
27
|
+
if word == "("
|
|
28
|
+
")"
|
|
29
|
+
elsif word == ")"
|
|
30
|
+
"("
|
|
31
|
+
else
|
|
32
|
+
word
|
|
33
|
+
end
|
|
34
|
+
end.join(" ")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Left to Right expresstion starts with simple term instead of expression
|
|
38
|
+
def left_to_right?
|
|
39
|
+
return true unless sentence
|
|
40
|
+
|
|
41
|
+
sentence[0] != "("
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Add whitespace before/after parentheses
|
|
45
|
+
def prepared_sentence
|
|
46
|
+
if sentence
|
|
47
|
+
sentence.split("").reduce("") do |left_to_right_string, char|
|
|
48
|
+
left_to_right_string + (["(", ")"].include?(char) ? " #{char} " : char)
|
|
49
|
+
end
|
|
50
|
+
else
|
|
51
|
+
""
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require "parslet"
|
|
2
|
+
require "ostruct"
|
|
3
|
+
require_relative "elasticsearch_query_parser/sentence"
|
|
4
|
+
require_relative "elasticsearch_query_parser/grammar/parser"
|
|
5
|
+
require_relative "elasticsearch_query_parser/grammar/transformer"
|
|
6
|
+
|
|
7
|
+
# Mail ElasticsearchQueryParser interface
|
|
8
|
+
module ElasticsearchQueryParser
|
|
9
|
+
# Gem configuration object
|
|
10
|
+
# For now only contain 1 attribute: `elastic_field_name` option (by default :text)
|
|
11
|
+
# Responds with OpenStruct entity which responds_to `elastic_field_name`
|
|
12
|
+
# Example:
|
|
13
|
+
# >> ElasticsearchQueryParser.configuration
|
|
14
|
+
# => #<OpenStruct elastic_field_name=:text>
|
|
15
|
+
def self.configuration
|
|
16
|
+
@configuration ||= OpenStruct.new(
|
|
17
|
+
elastic_field_name: :text
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# For gem configuration
|
|
22
|
+
# For now only `elastic_field_name` can be modified. See README.md for details
|
|
23
|
+
def self.configure
|
|
24
|
+
yield(configuration)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Parse given string into Elastic query object (see README.md for more examples)
|
|
28
|
+
# Example:
|
|
29
|
+
# >> ElasticsearchQueryParser.parse_query("London")
|
|
30
|
+
# => { query: { bool: { should: [{ match: { text: { query: "London", operator: "and" } } }] } } }
|
|
31
|
+
def self.parse_query(user_query)
|
|
32
|
+
query = Sentence.new(user_query).to_s
|
|
33
|
+
|
|
34
|
+
return {} if query.to_s.empty?
|
|
35
|
+
|
|
36
|
+
parse_tree = Grammar::Parser.new.parse(query)
|
|
37
|
+
transformed_query = Grammar::Transformer.new.apply(parse_tree)
|
|
38
|
+
{ query: transformed_query.to_elasticsearch }
|
|
39
|
+
rescue Parslet::ParseFailed => e
|
|
40
|
+
raise ParseFailedException, e.parse_failure_cause
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class ParseFailedException < StandardError
|
|
44
|
+
attr_reader :parse_failure_cause
|
|
45
|
+
private :parse_failure_cause
|
|
46
|
+
|
|
47
|
+
def initialize(parse_failure_cause)
|
|
48
|
+
@parse_failure_cause = parse_failure_cause
|
|
49
|
+
super
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: elasticsearch_query_parser
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.4
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Ruslan Khabibullin
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2020-07-25 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rspec
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '3.9'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '3.9'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: parslet
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '2.0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '2.0'
|
|
41
|
+
description: Convert user queries like `(London OR Paris) AND 'John Wick'` into elasticsearch
|
|
42
|
+
JSON queries
|
|
43
|
+
email: khabibullin.ruslan.95@gmail.com
|
|
44
|
+
executables: []
|
|
45
|
+
extensions: []
|
|
46
|
+
extra_rdoc_files: []
|
|
47
|
+
files:
|
|
48
|
+
- LICENSE
|
|
49
|
+
- README.md
|
|
50
|
+
- lib/doc/ElasticsearchQueryParser.html
|
|
51
|
+
- lib/doc/ElasticsearchQueryParser/Grammar.html
|
|
52
|
+
- lib/doc/ElasticsearchQueryParser/Grammar/Parser.html
|
|
53
|
+
- lib/doc/ElasticsearchQueryParser/Grammar/Presenters.html
|
|
54
|
+
- lib/doc/ElasticsearchQueryParser/Grammar/Presenters/Operator.html
|
|
55
|
+
- lib/doc/ElasticsearchQueryParser/Grammar/Presenters/Operator/InvalidOperatorString.html
|
|
56
|
+
- lib/doc/ElasticsearchQueryParser/Grammar/Presenters/Query.html
|
|
57
|
+
- lib/doc/ElasticsearchQueryParser/Grammar/Presenters/Term.html
|
|
58
|
+
- lib/doc/ElasticsearchQueryParser/Grammar/Transformer.html
|
|
59
|
+
- lib/doc/ElasticsearchQueryParser/ParseFailedException.html
|
|
60
|
+
- lib/doc/ElasticsearchQueryParser/Sentence.html
|
|
61
|
+
- lib/doc/created.rid
|
|
62
|
+
- lib/doc/css/fonts.css
|
|
63
|
+
- lib/doc/css/rdoc.css
|
|
64
|
+
- lib/doc/fonts/Lato-Light.ttf
|
|
65
|
+
- lib/doc/fonts/Lato-LightItalic.ttf
|
|
66
|
+
- lib/doc/fonts/Lato-Regular.ttf
|
|
67
|
+
- lib/doc/fonts/Lato-RegularItalic.ttf
|
|
68
|
+
- lib/doc/fonts/SourceCodePro-Bold.ttf
|
|
69
|
+
- lib/doc/fonts/SourceCodePro-Regular.ttf
|
|
70
|
+
- lib/doc/images/add.png
|
|
71
|
+
- lib/doc/images/arrow_up.png
|
|
72
|
+
- lib/doc/images/brick.png
|
|
73
|
+
- lib/doc/images/brick_link.png
|
|
74
|
+
- lib/doc/images/bug.png
|
|
75
|
+
- lib/doc/images/bullet_black.png
|
|
76
|
+
- lib/doc/images/bullet_toggle_minus.png
|
|
77
|
+
- lib/doc/images/bullet_toggle_plus.png
|
|
78
|
+
- lib/doc/images/date.png
|
|
79
|
+
- lib/doc/images/delete.png
|
|
80
|
+
- lib/doc/images/find.png
|
|
81
|
+
- lib/doc/images/loadingAnimation.gif
|
|
82
|
+
- lib/doc/images/macFFBgHack.png
|
|
83
|
+
- lib/doc/images/package.png
|
|
84
|
+
- lib/doc/images/page_green.png
|
|
85
|
+
- lib/doc/images/page_white_text.png
|
|
86
|
+
- lib/doc/images/page_white_width.png
|
|
87
|
+
- lib/doc/images/plugin.png
|
|
88
|
+
- lib/doc/images/ruby.png
|
|
89
|
+
- lib/doc/images/tag_blue.png
|
|
90
|
+
- lib/doc/images/tag_green.png
|
|
91
|
+
- lib/doc/images/transparent.png
|
|
92
|
+
- lib/doc/images/wrench.png
|
|
93
|
+
- lib/doc/images/wrench_orange.png
|
|
94
|
+
- lib/doc/images/zoom.png
|
|
95
|
+
- lib/doc/index.html
|
|
96
|
+
- lib/doc/js/darkfish.js
|
|
97
|
+
- lib/doc/js/navigation.js
|
|
98
|
+
- lib/doc/js/navigation.js.gz
|
|
99
|
+
- lib/doc/js/search.js
|
|
100
|
+
- lib/doc/js/search_index.js
|
|
101
|
+
- lib/doc/js/search_index.js.gz
|
|
102
|
+
- lib/doc/js/searcher.js
|
|
103
|
+
- lib/doc/js/searcher.js.gz
|
|
104
|
+
- lib/doc/table_of_contents.html
|
|
105
|
+
- lib/elasticsearch_query_parser.rb
|
|
106
|
+
- lib/elasticsearch_query_parser/grammar/parser.rb
|
|
107
|
+
- lib/elasticsearch_query_parser/grammar/presenters/operator.rb
|
|
108
|
+
- lib/elasticsearch_query_parser/grammar/presenters/query.rb
|
|
109
|
+
- lib/elasticsearch_query_parser/grammar/presenters/term.rb
|
|
110
|
+
- lib/elasticsearch_query_parser/grammar/transformer.rb
|
|
111
|
+
- lib/elasticsearch_query_parser/sentence.rb
|
|
112
|
+
homepage: https://github.com/RuslanKhabibullin/elasticsearch_query_parser
|
|
113
|
+
licenses:
|
|
114
|
+
- MIT
|
|
115
|
+
metadata: {}
|
|
116
|
+
post_install_message:
|
|
117
|
+
rdoc_options: []
|
|
118
|
+
require_paths:
|
|
119
|
+
- lib
|
|
120
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - ">="
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '0'
|
|
125
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
126
|
+
requirements:
|
|
127
|
+
- - ">="
|
|
128
|
+
- !ruby/object:Gem::Version
|
|
129
|
+
version: '0'
|
|
130
|
+
requirements: []
|
|
131
|
+
rubygems_version: 3.0.3
|
|
132
|
+
signing_key:
|
|
133
|
+
specification_version: 4
|
|
134
|
+
summary: Parse user queries into Elastic query
|
|
135
|
+
test_files: []
|