qiita-elasticsearch 0.3.0 → 0.4.0
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 +4 -4
- data/.rubocop.yml +4 -0
- data/CHANGELOG.md +7 -0
- data/README.md +26 -5
- data/lib/qiita/elasticsearch/concerns/range_operand_includable.rb +42 -0
- data/lib/qiita/elasticsearch/date_token.rb +93 -0
- data/lib/qiita/elasticsearch/errors.rb +10 -0
- data/lib/qiita/elasticsearch/int_token.rb +35 -0
- data/lib/qiita/elasticsearch/query_builder.rb +15 -6
- data/lib/qiita/elasticsearch/range_token.rb +3 -3
- data/lib/qiita/elasticsearch/tokenizer.rb +22 -9
- data/lib/qiita/elasticsearch/version.rb +1 -1
- data/qiita-elasticsearch.gemspec +1 -0
- metadata +21 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 133b6b66d4231ea9d97e516812cc58b232981319
|
4
|
+
data.tar.gz: b70d9f047d78e461e4cd81a076e5f09418982682
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d9776c15e61239299ec17682c62930e2fddade09934cccf08f236a8e85f38bb8788fc34703323a4e49d66094bc19c494a4b8e7cd6c3a567bdebab0a5b564e68
|
7
|
+
data.tar.gz: 93d80c35c9135c8f3cb0837731fccd55b60cca6a912e9a36e1f641f71984b7f815b1d945c2a9836295fad9389ecec433566a5c457907759f0157c027caeb7b7d
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
## 0.4.0
|
2
|
+
- Change range fields to use integer
|
3
|
+
- Support date fields
|
4
|
+
- Support time_zone parameter
|
5
|
+
- Rename range_fields parameter as int_fields
|
6
|
+
- Return a null query if an invalid query string is given
|
7
|
+
|
1
8
|
## 0.3.0
|
2
9
|
- Add downcased_fields options and update case rule
|
3
10
|
|
data/README.md
CHANGED
@@ -60,15 +60,36 @@ query_builder.build("tag:ruby")
|
|
60
60
|
#=> {"filtered"=>{"filter"=>{"bool"=>{"should"=>[{"prefix"=>{"tag"=>"ruby/"}}, {"term"=>{"tag"=>"ruby"}}]}}}}
|
61
61
|
```
|
62
62
|
|
63
|
-
###
|
64
|
-
Pass `:
|
65
|
-
With this option, `
|
63
|
+
### int_fields
|
64
|
+
Pass `:int_fields` option with `:filterable_fields` to enable range filtered queries.
|
65
|
+
With this option, `stocks:>100` will hit documents stocked by greater than 100 users.
|
66
66
|
|
67
67
|
```rb
|
68
|
-
query_builder = Qiita::Elasticsearch::QueryBuilder.new(filterable_fields: ["
|
68
|
+
query_builder = Qiita::Elasticsearch::QueryBuilder.new(filterable_fields: ["stocks"], int_fields: ["stocks"])
|
69
|
+
|
70
|
+
query_builder.build("stocks:>100")
|
71
|
+
#=> {"filtered"=>{"filter"=>{"range"=>{"stocks"=>{"gt"=>100}}}}}
|
72
|
+
```
|
73
|
+
|
74
|
+
### date_fields
|
75
|
+
Pass `:date_fields` option with `:filterable_fields` to enable date filtered queries.
|
76
|
+
With this option, `created_at:<2015-04-01` will hit documents created before 2015-04-01.
|
77
|
+
|
78
|
+
```rb
|
79
|
+
query_builder = Qiita::Elasticsearch::QueryBuilder.new(filterable_fields: ["created_at"], date_fields: ["created_at"])
|
80
|
+
|
81
|
+
query_builder.build("created_at:<2015-04-01")
|
82
|
+
#=> {"filtered"=>{"filter"=>{"range"=>{"created_at"=>{"lt"=>"2015-04-01"}}}}}
|
83
|
+
```
|
84
|
+
|
85
|
+
### time_zone
|
86
|
+
Pass `:time_zone` option to tell how move range field's input to UTC time based date.
|
87
|
+
|
88
|
+
```rb
|
89
|
+
query_builder = Qiita::Elasticsearch::QueryBuilder.new(filterable_fields: ["created_at"], date_fields: ["created_at"], time_zone: "+09:00")
|
69
90
|
|
70
91
|
query_builder.build("created_at:<2015-04-16")
|
71
|
-
#=> {"filtered"=>{"filter"=>{"range"=>{"created_at"=>{"lt"=>"2015-04-16"}}}}}
|
92
|
+
#=> {"filtered"=>{"filter"=>{"range"=>{"created_at"=>{"lt"=>"2015-04-16","time_zone"=>"+09:00"}}}}}
|
72
93
|
```
|
73
94
|
|
74
95
|
### downcased_fields
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "active_support/concern"
|
2
|
+
|
3
|
+
module Qiita
|
4
|
+
module Elasticsearch
|
5
|
+
module Concerns
|
6
|
+
module RangeOperandIncludable
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
RANGE_TERM_REGEXP = /\A(?<operand>\<=|\<|\>=|\>)(?<query>.*)\z/
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
# @return [String, nil]
|
14
|
+
# @example Suppose @term is "created_at:>=2015-04-16"
|
15
|
+
# range_parameter #=> "gte"
|
16
|
+
def range_parameter
|
17
|
+
range_match[:operand] ? operand_map[range_match[:operand]] : nil
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [String, nil]
|
21
|
+
# @example Suppose @term is "created_at:>=2015-04-16"
|
22
|
+
# range_query #=> "2015-04-16"
|
23
|
+
def range_query
|
24
|
+
range_match[:query]
|
25
|
+
end
|
26
|
+
|
27
|
+
def range_match
|
28
|
+
@range_match ||= RANGE_TERM_REGEXP.match(@term) || {}
|
29
|
+
end
|
30
|
+
|
31
|
+
def operand_map
|
32
|
+
{
|
33
|
+
">" => "gt",
|
34
|
+
">=" => "gte",
|
35
|
+
"<" => "lt",
|
36
|
+
"<=" => "lte",
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require "active_support/core_ext/date"
|
2
|
+
require "active_support/core_ext/integer"
|
3
|
+
require "qiita/elasticsearch/concerns/range_operand_includable"
|
4
|
+
require "qiita/elasticsearch/errors"
|
5
|
+
require "qiita/elasticsearch/token"
|
6
|
+
|
7
|
+
module Qiita
|
8
|
+
module Elasticsearch
|
9
|
+
class DateToken < Token
|
10
|
+
include Concerns::RangeOperandIncludable
|
11
|
+
|
12
|
+
# @note Matches to "YYYY", "YYYY-MM" and "YYYY-MM-DD"
|
13
|
+
DATE_PATTERN = /\A
|
14
|
+
(?<year>\d{4})
|
15
|
+
(?:
|
16
|
+
-
|
17
|
+
(?<month>\d{1,2})
|
18
|
+
(?:
|
19
|
+
-
|
20
|
+
(?<day>\d{1,2})
|
21
|
+
)?
|
22
|
+
)?
|
23
|
+
\z/x
|
24
|
+
|
25
|
+
attr_writer :time_zone
|
26
|
+
|
27
|
+
# @return [Hash]
|
28
|
+
# @raise [InvalidQuery]
|
29
|
+
def to_hash
|
30
|
+
if date_match
|
31
|
+
if range_parameter
|
32
|
+
{
|
33
|
+
"range" => {
|
34
|
+
@field_name => {
|
35
|
+
range_parameter => range_query,
|
36
|
+
"time_zone" => @time_zone,
|
37
|
+
}.reject do |key, value|
|
38
|
+
key == "time_zone" && value.nil?
|
39
|
+
end,
|
40
|
+
},
|
41
|
+
}
|
42
|
+
else
|
43
|
+
{
|
44
|
+
"range" => {
|
45
|
+
@field_name => {
|
46
|
+
"gte" => beginning_of_range.to_s,
|
47
|
+
"lt" => end_of_range.to_s,
|
48
|
+
"time_zone" => @time_zone,
|
49
|
+
}.reject do |key, value|
|
50
|
+
key == "time_zone" && value.nil?
|
51
|
+
end,
|
52
|
+
},
|
53
|
+
}
|
54
|
+
end
|
55
|
+
else
|
56
|
+
fail InvalidQuery
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def date_match
|
63
|
+
@date_match ||= DATE_PATTERN.match(range_query || @term)
|
64
|
+
end
|
65
|
+
|
66
|
+
# @return [Date]
|
67
|
+
def beginning_of_range
|
68
|
+
@beginning_of_range ||=
|
69
|
+
case
|
70
|
+
when date_match[:day]
|
71
|
+
Date.new(date_match[:year].to_i, date_match[:month].to_i, date_match[:day].to_i)
|
72
|
+
when date_match[:month]
|
73
|
+
Date.new(date_match[:year].to_i, date_match[:month].to_i)
|
74
|
+
else
|
75
|
+
Date.new(date_match[:year].to_i)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# @return [Date]
|
80
|
+
def end_of_range
|
81
|
+
@end_of_range ||=
|
82
|
+
case
|
83
|
+
when date_match[:day]
|
84
|
+
beginning_of_range + 1.day
|
85
|
+
when date_match[:month]
|
86
|
+
beginning_of_range + 1.month
|
87
|
+
else
|
88
|
+
beginning_of_range + 1.year
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "qiita/elasticsearch/concerns/range_operand_includable"
|
2
|
+
require "qiita/elasticsearch/errors"
|
3
|
+
require "qiita/elasticsearch/token"
|
4
|
+
|
5
|
+
module Qiita
|
6
|
+
module Elasticsearch
|
7
|
+
class IntToken < Token
|
8
|
+
include Concerns::RangeOperandIncludable
|
9
|
+
|
10
|
+
INT_PATTERN = /\A\d+\z/
|
11
|
+
|
12
|
+
# @return [Hash]
|
13
|
+
# @raise [InvalidQuery]
|
14
|
+
def to_hash
|
15
|
+
if range_parameter && INT_PATTERN =~ range_query
|
16
|
+
{
|
17
|
+
"range" => {
|
18
|
+
@field_name => {
|
19
|
+
range_parameter => range_query.to_i,
|
20
|
+
},
|
21
|
+
},
|
22
|
+
}
|
23
|
+
elsif INT_PATTERN =~ @term
|
24
|
+
{
|
25
|
+
"term" => {
|
26
|
+
@field_name => @term.to_i,
|
27
|
+
},
|
28
|
+
}
|
29
|
+
else
|
30
|
+
fail InvalidQuery
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require "qiita/elasticsearch/errors"
|
1
2
|
require "qiita/elasticsearch/nodes/null_node"
|
2
3
|
require "qiita/elasticsearch/nodes/or_separatable_node"
|
3
4
|
require "qiita/elasticsearch/tokenizer"
|
@@ -5,17 +6,21 @@ require "qiita/elasticsearch/tokenizer"
|
|
5
6
|
module Qiita
|
6
7
|
module Elasticsearch
|
7
8
|
class QueryBuilder
|
9
|
+
# @param [Array<String>, nil] date_fields
|
8
10
|
# @param [Array<String>, nil] downcased_fields
|
9
11
|
# @param [Array<String>, nil] filterable_fields
|
10
12
|
# @param [Array<String>, nil] hierarchal_fields
|
13
|
+
# @param [Array<String>, nil] int_fields
|
11
14
|
# @param [Array<String>, nil] matchable_fields
|
12
|
-
# @param [
|
13
|
-
def initialize(downcased_fields: nil, hierarchal_fields: nil, filterable_fields: nil, matchable_fields: nil,
|
15
|
+
# @param [String, nil] time_zone
|
16
|
+
def initialize(date_fields: nil, downcased_fields: nil, hierarchal_fields: nil, filterable_fields: nil, int_fields: nil, matchable_fields: nil, time_zone: nil)
|
17
|
+
@date_fields = date_fields
|
14
18
|
@downcased_fields = downcased_fields
|
15
|
-
@hierarchal_fields = hierarchal_fields
|
16
19
|
@filterable_fields = filterable_fields
|
20
|
+
@hierarchal_fields = hierarchal_fields
|
21
|
+
@int_fields = int_fields
|
17
22
|
@matchable_fields = matchable_fields
|
18
|
-
@
|
23
|
+
@time_zone = time_zone
|
19
24
|
end
|
20
25
|
|
21
26
|
# @param [String] query_string Raw query string
|
@@ -27,17 +32,21 @@ module Qiita
|
|
27
32
|
else
|
28
33
|
Nodes::OrSeparatableNode.new(tokens).to_hash
|
29
34
|
end
|
35
|
+
rescue Error
|
36
|
+
Nodes::NullNode.new.to_hash
|
30
37
|
end
|
31
38
|
|
32
39
|
private
|
33
40
|
|
34
41
|
def tokenizer
|
35
42
|
@tokenizer ||= Tokenizer.new(
|
43
|
+
date_fields: @date_fields,
|
36
44
|
downcased_fields: @downcased_fields,
|
37
|
-
hierarchal_fields: @hierarchal_fields,
|
38
45
|
filterable_fields: @filterable_fields,
|
46
|
+
hierarchal_fields: @hierarchal_fields,
|
47
|
+
int_fields: @int_fields,
|
39
48
|
matchable_fields: @matchable_fields,
|
40
|
-
|
49
|
+
time_zone: @time_zone,
|
41
50
|
)
|
42
51
|
end
|
43
52
|
end
|
@@ -3,7 +3,7 @@ require "qiita/elasticsearch/token"
|
|
3
3
|
module Qiita
|
4
4
|
module Elasticsearch
|
5
5
|
class RangeToken < Token
|
6
|
-
RANGE_TERM_REGEXP = /\A(?<operand
|
6
|
+
RANGE_TERM_REGEXP = /\A(?<operand>\<=|\<|\>=|\>)(?<query>.*)\z/
|
7
7
|
|
8
8
|
# @return [Hash]
|
9
9
|
def to_hash
|
@@ -11,14 +11,14 @@ module Qiita
|
|
11
11
|
{
|
12
12
|
"range" => {
|
13
13
|
@field_name => {
|
14
|
-
range_parameter => range_query,
|
14
|
+
range_parameter => range_query.to_i,
|
15
15
|
},
|
16
16
|
},
|
17
17
|
}
|
18
18
|
else
|
19
19
|
{
|
20
20
|
"term" => {
|
21
|
-
@field_name => proper_cased_term,
|
21
|
+
@field_name => proper_cased_term.to_i,
|
22
22
|
},
|
23
23
|
}
|
24
24
|
end
|
@@ -1,15 +1,17 @@
|
|
1
|
+
require "qiita/elasticsearch/date_token"
|
1
2
|
require "qiita/elasticsearch/filterable_token"
|
2
3
|
require "qiita/elasticsearch/hierarchal_token"
|
3
4
|
require "qiita/elasticsearch/matchable_token"
|
4
|
-
require "qiita/elasticsearch/
|
5
|
+
require "qiita/elasticsearch/int_token"
|
5
6
|
|
6
7
|
module Qiita
|
7
8
|
module Elasticsearch
|
8
9
|
class Tokenizer
|
10
|
+
DEFAULT_DATE_FIELDS = []
|
9
11
|
DEFAULT_DOWNCASED_FIELDS = []
|
10
12
|
DEFAULT_FILTERABLE_FIELDS = []
|
11
13
|
DEFAULT_HIERARCHAL_FIELDS = []
|
12
|
-
|
14
|
+
DEFAULT_INT_FIELDS = []
|
13
15
|
|
14
16
|
TOKEN_PATTERN = /
|
15
17
|
(?<token_string>
|
@@ -23,17 +25,21 @@ module Qiita
|
|
23
25
|
)
|
24
26
|
/x
|
25
27
|
|
28
|
+
# @param [Array<String>, nil] date_fields
|
26
29
|
# @param [Array<String>, nil] downcased_fields
|
27
30
|
# @param [Array<String>, nil] filterable_fields
|
28
31
|
# @param [Array<String>, nil] hierarchal_fields
|
32
|
+
# @param [Array<String>, nil] int_fields
|
29
33
|
# @param [Array<String>, nil] matchable_fields
|
30
|
-
# @param [
|
31
|
-
def initialize(downcased_fields: nil, filterable_fields: nil, hierarchal_fields: nil, matchable_fields: nil,
|
34
|
+
# @param [String, nil] time_zone
|
35
|
+
def initialize(date_fields: nil, downcased_fields: nil, filterable_fields: nil, hierarchal_fields: nil, int_fields: nil, matchable_fields: nil, time_zone: nil)
|
36
|
+
@date_fields = date_fields
|
32
37
|
@downcased_fields = downcased_fields
|
33
38
|
@filterable_fields = filterable_fields
|
34
39
|
@hierarchal_fields = hierarchal_fields
|
40
|
+
@int_fields = int_fields
|
35
41
|
@matchable_fields = matchable_fields
|
36
|
-
@
|
42
|
+
@time_zone = time_zone
|
37
43
|
end
|
38
44
|
|
39
45
|
# @param [String] query_string Raw query string
|
@@ -54,12 +60,17 @@ module Qiita
|
|
54
60
|
token_string: token_string,
|
55
61
|
)
|
56
62
|
token.matchable_fields = @matchable_fields if token.is_a?(MatchableToken)
|
63
|
+
token.time_zone = @time_zone if token.is_a?(DateToken)
|
57
64
|
token
|
58
65
|
end
|
59
66
|
end
|
60
67
|
|
61
68
|
private
|
62
69
|
|
70
|
+
def date_fields
|
71
|
+
@date_fields || DEFAULT_DATE_FIELDS
|
72
|
+
end
|
73
|
+
|
63
74
|
def downcased_fields
|
64
75
|
@downcased_fields || DEFAULT_DOWNCASED_FIELDS
|
65
76
|
end
|
@@ -72,14 +83,16 @@ module Qiita
|
|
72
83
|
@hierarchal_fields || DEFAULT_HIERARCHAL_FIELDS
|
73
84
|
end
|
74
85
|
|
75
|
-
def
|
76
|
-
@
|
86
|
+
def int_fields
|
87
|
+
@int_fields || DEFAULT_INT_FIELDS
|
77
88
|
end
|
78
89
|
|
79
90
|
def token_class(field_name)
|
80
91
|
case
|
81
|
-
when
|
82
|
-
|
92
|
+
when date_fields.include?(field_name)
|
93
|
+
DateToken
|
94
|
+
when int_fields.include?(field_name)
|
95
|
+
IntToken
|
83
96
|
when hierarchal_fields.include?(field_name)
|
84
97
|
HierarchalToken
|
85
98
|
when filterable_fields.include?(field_name)
|
data/qiita-elasticsearch.gemspec
CHANGED
@@ -14,6 +14,7 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.bindir = "bin"
|
15
15
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
16
16
|
spec.require_paths = ["lib"]
|
17
|
+
spec.add_dependency "activesupport"
|
17
18
|
spec.add_development_dependency "bundler", ">= 1.7"
|
18
19
|
spec.add_development_dependency "codeclimate-test-reporter"
|
19
20
|
spec.add_development_dependency "rake", "~> 10.0"
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qiita-elasticsearch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryo Nakamura
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -97,8 +111,12 @@ files:
|
|
97
111
|
- README.md
|
98
112
|
- Rakefile
|
99
113
|
- lib/qiita/elasticsearch.rb
|
114
|
+
- lib/qiita/elasticsearch/concerns/range_operand_includable.rb
|
115
|
+
- lib/qiita/elasticsearch/date_token.rb
|
116
|
+
- lib/qiita/elasticsearch/errors.rb
|
100
117
|
- lib/qiita/elasticsearch/filterable_token.rb
|
101
118
|
- lib/qiita/elasticsearch/hierarchal_token.rb
|
119
|
+
- lib/qiita/elasticsearch/int_token.rb
|
102
120
|
- lib/qiita/elasticsearch/matchable_token.rb
|
103
121
|
- lib/qiita/elasticsearch/nodes/filter_node.rb
|
104
122
|
- lib/qiita/elasticsearch/nodes/filterable_node.rb
|
@@ -134,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
134
152
|
version: '0'
|
135
153
|
requirements: []
|
136
154
|
rubyforge_project:
|
137
|
-
rubygems_version: 2.
|
155
|
+
rubygems_version: 2.2.2
|
138
156
|
signing_key:
|
139
157
|
specification_version: 4
|
140
158
|
summary: Elasticsearch client helper for Qiita.
|