mm_es_search 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/.gitignore +4 -0
  2. data/.project +18 -0
  3. data/Gemfile +4 -0
  4. data/Rakefile +1 -0
  5. data/lib/mm_es_search/api/facet/abstract_facet.rb +28 -0
  6. data/lib/mm_es_search/api/facet/date_histogram_facet.rb +11 -0
  7. data/lib/mm_es_search/api/facet/filter_facet.rb +9 -0
  8. data/lib/mm_es_search/api/facet/geo_distance_facet.rb +9 -0
  9. data/lib/mm_es_search/api/facet/histogram_facet.rb +9 -0
  10. data/lib/mm_es_search/api/facet/query_facet.rb +9 -0
  11. data/lib/mm_es_search/api/facet/range_facet.rb +36 -0
  12. data/lib/mm_es_search/api/facet/range_facet_row.rb +97 -0
  13. data/lib/mm_es_search/api/facet/range_item.rb +17 -0
  14. data/lib/mm_es_search/api/facet/statistical_facet.rb +33 -0
  15. data/lib/mm_es_search/api/facet/statistical_facet_result.rb +36 -0
  16. data/lib/mm_es_search/api/facet/terms_facet.rb +62 -0
  17. data/lib/mm_es_search/api/facet/terms_facet_row.rb +35 -0
  18. data/lib/mm_es_search/api/facet/terms_stats_facet.rb +9 -0
  19. data/lib/mm_es_search/api/highlight/result_highlight.rb +40 -0
  20. data/lib/mm_es_search/api/query/abstract_filter.rb +15 -0
  21. data/lib/mm_es_search/api/query/abstract_query.rb +48 -0
  22. data/lib/mm_es_search/api/query/and_filter.rb +9 -0
  23. data/lib/mm_es_search/api/query/bool_filter.rb +11 -0
  24. data/lib/mm_es_search/api/query/bool_query.rb +67 -0
  25. data/lib/mm_es_search/api/query/constant_score_query.rb +31 -0
  26. data/lib/mm_es_search/api/query/custom_filters_score_query.rb +52 -0
  27. data/lib/mm_es_search/api/query/custom_score_query.rb +31 -0
  28. data/lib/mm_es_search/api/query/dismax_query.rb +29 -0
  29. data/lib/mm_es_search/api/query/filtered_query.rb +30 -0
  30. data/lib/mm_es_search/api/query/has_child_filter.rb +11 -0
  31. data/lib/mm_es_search/api/query/has_child_query.rb +25 -0
  32. data/lib/mm_es_search/api/query/has_parent_filter.rb +11 -0
  33. data/lib/mm_es_search/api/query/has_parent_query.rb +25 -0
  34. data/lib/mm_es_search/api/query/match_all_filter.rb +11 -0
  35. data/lib/mm_es_search/api/query/match_all_query.rb +19 -0
  36. data/lib/mm_es_search/api/query/nested_filter.rb +22 -0
  37. data/lib/mm_es_search/api/query/nested_query.rb +62 -0
  38. data/lib/mm_es_search/api/query/not_filter.rb +9 -0
  39. data/lib/mm_es_search/api/query/or_filter.rb +9 -0
  40. data/lib/mm_es_search/api/query/prefix_filter.rb +11 -0
  41. data/lib/mm_es_search/api/query/prefix_query.rb +34 -0
  42. data/lib/mm_es_search/api/query/query_filter.rb +28 -0
  43. data/lib/mm_es_search/api/query/query_string_query.rb +37 -0
  44. data/lib/mm_es_search/api/query/range_filter.rb +11 -0
  45. data/lib/mm_es_search/api/query/range_query.rb +57 -0
  46. data/lib/mm_es_search/api/query/scored_filter.rb +29 -0
  47. data/lib/mm_es_search/api/query/single_bool_filter.rb +66 -0
  48. data/lib/mm_es_search/api/query/term_filter.rb +11 -0
  49. data/lib/mm_es_search/api/query/term_query.rb +34 -0
  50. data/lib/mm_es_search/api/query/terms_filter.rb +11 -0
  51. data/lib/mm_es_search/api/query/terms_query.rb +58 -0
  52. data/lib/mm_es_search/api/query/text_query.rb +42 -0
  53. data/lib/mm_es_search/api/query/top_children_query.rb +28 -0
  54. data/lib/mm_es_search/api/sort/root_sort.rb +36 -0
  55. data/lib/mm_es_search/models/abstract_facet_model.rb +23 -0
  56. data/lib/mm_es_search/models/abstract_query_model.rb +21 -0
  57. data/lib/mm_es_search/models/abstract_range_facet_model.rb +365 -0
  58. data/lib/mm_es_search/models/abstract_search_model.OLD +538 -0
  59. data/lib/mm_es_search/models/abstract_search_model.rb +521 -0
  60. data/lib/mm_es_search/models/abstract_sort_model.rb +13 -0
  61. data/lib/mm_es_search/models/abstract_terms_facet_model.rb +87 -0
  62. data/lib/mm_es_search/models/root_sort_model.rb +20 -0
  63. data/lib/mm_es_search/models/virtual_field_sort.rb +52 -0
  64. data/lib/mm_es_search/utils/facet_row_utils.rb +86 -0
  65. data/lib/mm_es_search/utils/search_logger.rb +10 -0
  66. data/lib/mm_es_search/version.rb +3 -0
  67. data/lib/mm_es_search.rb +124 -0
  68. data/mm_es_search.gemspec +24 -0
  69. metadata +132 -0
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.project ADDED
@@ -0,0 +1,18 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <projectDescription>
3
+ <name>mm_es_search</name>
4
+ <comment></comment>
5
+ <projects>
6
+ </projects>
7
+ <buildSpec>
8
+ <buildCommand>
9
+ <name>com.aptana.ide.core.unifiedBuilder</name>
10
+ <arguments>
11
+ </arguments>
12
+ </buildCommand>
13
+ </buildSpec>
14
+ <natures>
15
+ <nature>org.radrails.rails.core.railsnature</nature>
16
+ <nature>com.aptana.ruby.core.rubynature</nature>
17
+ </natures>
18
+ </projectDescription>
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in mm_es_search.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,28 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Facet
4
+
5
+ class AbstractFacet
6
+
7
+ include MongoMapper::EmbeddedDocument
8
+ include MmEsSearch::Api::Query
9
+ plugin MmUsesNoId
10
+
11
+ key :label, String
12
+ key :nested, String
13
+ key :scope, String
14
+ one :facet_filter, :class_name => 'MmEsSearch::Api::Query::AbstractQuery'
15
+
16
+ def to_es_query
17
+ facet_params = {}
18
+ facet_params.merge!(:scope => scope) if scope?
19
+ facet_params.merge!(:nested => nested) if nested?
20
+ facet_params.merge!(:facet_filter => facet_filter.to_es_query) if facet_filter?
21
+ return facet_params
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,11 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Facet
4
+
5
+ class DateHistogramFacet < AbstractFacet
6
+
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Facet
4
+
5
+
6
+
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Facet
4
+
5
+
6
+
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Facet
4
+
5
+
6
+
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Facet
4
+
5
+
6
+
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,36 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Facet
4
+
5
+ class RangeFacet < AbstractFacet
6
+
7
+ key :field, String
8
+ many :ranges, :class_name => 'MmEsSearch::Api::Facet::RangeItem'
9
+ key :key_field, String
10
+ key :value_field, String
11
+ key :key_script, String
12
+ key :value_script, String
13
+ key :params, Hash
14
+
15
+ def to_es_query
16
+
17
+ range_params = {}
18
+ range_params.merge!(:field => field) if field?
19
+ range_params.merge!(:ranges => ranges.map(&:attributes))
20
+ range_params.merge!(:key_field => size) if key_field?
21
+ range_params.merge!(:value_field => size) if value_field?
22
+ range_params.merge!(:key_script => size) if key_script?
23
+ range_params.merge!(:value_script => size) if value_script?
24
+ range_params.merge!(:params => params) unless params.empty?
25
+
26
+ facet_params = {:range => range_params}.merge(super)
27
+
28
+ return {label => facet_params}
29
+
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,97 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Facet
4
+
5
+ class RangeFacetRow
6
+
7
+ include MongoMapper::EmbeddedDocument
8
+ include ActionView::Helpers::NumberHelper
9
+ plugin MmUsesUuid
10
+
11
+ key :from
12
+ key :to
13
+ key :count, Integer
14
+ key :min
15
+ key :max
16
+ key :total_count, Integer
17
+ key :total
18
+ key :mean
19
+
20
+ key :checked, String
21
+
22
+ def from=(val)
23
+ super.tap do
24
+ binding.pry if from.is_a?(DateTime)
25
+ end
26
+ end
27
+
28
+ def attributes(*args)
29
+ attr = super
30
+ attr.each_with_object({}) do |(key, value), hsh|
31
+ hsh[key] = case value
32
+ when ActiveSupport::TimeWithZone
33
+ value.utc.to_time
34
+ else
35
+ value
36
+ end
37
+ end
38
+ end
39
+ alias :to_mongo :attributes
40
+
41
+ def zero_count
42
+ self.count = 0
43
+ end
44
+
45
+ def to_range_item
46
+ RangeItem.new(
47
+ :from => from,
48
+ :to => to
49
+ )
50
+ end
51
+
52
+ def to_english(pretty_print = true)
53
+ case from || to
54
+ when Numeric
55
+ render_numeric(pretty_print)
56
+ when Time, DateTime
57
+ end
58
+ end
59
+
60
+ def render_numeric(pretty_print)
61
+
62
+ if pretty_print
63
+ #TODO handle units (see http://bit.ly/rhx05t)
64
+ from_formatted = number_to_human(from) if from?
65
+ to_formatted = number_to_human(to) if to?
66
+ else
67
+ from_formatted = from if from?
68
+ to_formatted = to if to?
69
+ end
70
+
71
+ if from? and to?
72
+ "from #{from_formatted} to #{to_formatted}"
73
+ elsif from?
74
+ "#{from_formatted} or greater"
75
+ else
76
+ "upto #{to_formatted}"
77
+ end
78
+
79
+ end
80
+
81
+ def to_form_name(data_type)
82
+ params = []
83
+ params << "data_type:#{data_type}"
84
+ params << "from:#{from}" if from?
85
+ params << "to:#{to}" if to?
86
+ return params.join('&')
87
+ end
88
+
89
+ def parent
90
+ _parent_document
91
+ end
92
+
93
+ end
94
+
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,17 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Facet
4
+
5
+ class RangeItem
6
+
7
+ include MongoMapper::EmbeddedDocument
8
+ plugin MmUsesNoId
9
+
10
+ key :from
11
+ key :to
12
+
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,33 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Facet
4
+
5
+ class StatisticalFacet < AbstractFacet
6
+
7
+ key :field #Array or String
8
+ key :script, String
9
+ key :params, Hash
10
+
11
+ def to_es_query
12
+
13
+ stat_params = if script
14
+ script_params = {:script => script}
15
+ script_params.merge!({:params => params}) if params?
16
+ script_params
17
+ elsif field.is_a?(Array)
18
+ {:fields => field}
19
+ else
20
+ {:field => field}
21
+ end
22
+
23
+ facet_params = {:statistical => stat_params}.merge(super)
24
+
25
+ return {label => facet_params}
26
+
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,36 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Facet
4
+
5
+ class StatisticalFacetResult
6
+
7
+ include MongoMapper::EmbeddedDocument
8
+ plugin MmUsesNoId
9
+
10
+ key :count, Integer
11
+ key :total
12
+ key :sum_of_squares
13
+ key :mean
14
+ key :min
15
+ key :max
16
+ key :variance
17
+ key :std_deviation
18
+
19
+ def attributes(*args)
20
+ attr = super
21
+ attr.each_with_object({}) do |(key, value), hsh|
22
+ hsh[key] = case value
23
+ when ActiveSupport::TimeWithZone
24
+ value.utc.to_time
25
+ else
26
+ value
27
+ end
28
+ end
29
+ end
30
+ alias :to_mongo :attributes
31
+
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,62 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Facet
4
+
5
+ class TermsFacet < AbstractFacet
6
+
7
+ key :field #Array or String
8
+ key :path, String
9
+
10
+ key :size, Integer
11
+ key :order, String
12
+ key :exclude, Array #of Strings
13
+
14
+ key :script_field, String
15
+
16
+ key :regex, String
17
+ key :regex_flags, String
18
+
19
+ key :script, String
20
+ key :params, Hash
21
+
22
+ def qualified_field(field_name)
23
+ if path.present?
24
+ [path, field_name].join(".")
25
+ else
26
+ field_name
27
+ end
28
+ end
29
+
30
+ def to_es_query
31
+
32
+ mod_field = case field
33
+ when Array
34
+ field.map { |fname| qualified_field(fname) }
35
+ when String
36
+ qualified_field(field)
37
+ end
38
+
39
+ term_params = {}
40
+ term_params.merge!(:field => mod_field) if field.is_a?(String)
41
+ term_params.merge!(:fields => mod_field) if field.is_a?(Array)
42
+ term_params.merge!(:size => size) if (size? and size != 10)
43
+ term_params.merge!(:order => order) if (order? and order != "count")
44
+ term_params.merge!(:exclude => exclude) unless exclude.empty?
45
+ term_params.merge!(:script_field => script_field) if script_field?
46
+ term_params.merge!(:regex => regex) if regex?
47
+ term_params.merge!(:regex_flags => script_field) if regex_flags?
48
+ term_params.merge!(:script => script) if script?
49
+ term_params.merge!(:params => params) unless params.empty?
50
+
51
+ facet_params = {:terms => term_params}.merge(super)
52
+
53
+ return {label => facet_params}
54
+
55
+ end
56
+
57
+
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,35 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Facet
4
+
5
+ class TermsFacetRow
6
+
7
+ include MongoMapper::EmbeddedDocument
8
+ plugin MmUsesUuid
9
+
10
+ key :term, String
11
+ key :count, Integer
12
+
13
+ key :checked, String
14
+
15
+ def zero_count
16
+ self.count = 0
17
+ end
18
+
19
+ def to_english(pretty_print = true)
20
+ StringUtils.label_from_URI(term)
21
+ end
22
+
23
+ def to_form_name(data_type)
24
+ term
25
+ end
26
+
27
+ def parent
28
+ _parent_document
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,9 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Facet
4
+
5
+
6
+
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,40 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Highlight
4
+
5
+ class ResultHighlight
6
+
7
+ include MongoMapper::EmbeddedDocument
8
+ plugin MmUsesNoId
9
+
10
+ many :fields, :class_name => 'MmEsSearch::Api::Highlight::ResultHighlight'
11
+ key :field, String
12
+ key :tag_schema, String
13
+ key :pre_tags, Array
14
+ key :post_tags, Array
15
+ key :fragment_size, Integer
16
+ key :number_of_fragments, Integer
17
+ key :order, String
18
+
19
+ def to_mongo_query
20
+
21
+ raise "to_mongo_query not implemented for ResultHighlight"
22
+
23
+ end
24
+
25
+ def to_es_query
26
+
27
+ highlight_params = self.attributes.except("fields", "pre_tags", "post_tags")
28
+ highlight_params.merge!(:fields => fields.map(&:to_es_query)) unless fields.empty?
29
+ highlight_params.merge!(:pre_tags => pre_tags) unless pre_tags.empty?
30
+ highlight_params.merge!(:post_tags => post_tags) unless post_tags.empty?
31
+
32
+ return field? ? {field => highlight_params.except('field')} : highlight_params
33
+
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,15 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Query
4
+
5
+ module AbstractFilter
6
+ extend ActiveSupport::Concern
7
+
8
+ def to_filter
9
+ self
10
+ end
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,48 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Query
4
+
5
+ class AbstractQuery
6
+
7
+ include MongoMapper::EmbeddedDocument
8
+ plugin MmUsesNoId
9
+
10
+ def to_filter
11
+ QueryFilter.new(query: self)
12
+ end
13
+
14
+ def es_abs_field
15
+ if path?
16
+ mod_path, indx = path_and_index
17
+ return [mod_path, field].join('.')
18
+ else
19
+ return field
20
+ end
21
+ #TODO make sure we don't need to prefix path anymore - looks like we do if same name used at diff nesting levels, so always include to be safe
22
+ end
23
+
24
+ def mongo_abs_field
25
+ mod_path, array_index = path_and_index
26
+ return array_index.nil? ? field : [path, field].join('.')
27
+ end
28
+
29
+ def path_and_index
30
+
31
+ case path
32
+ when /(?<=\.)[0-9]+$/
33
+ mod_path = path.gsub(/\.[0-9]+/,'')
34
+ array_index = path.split('.').last.to_i
35
+ else
36
+ mod_path = path
37
+ array_index = nil
38
+ end
39
+
40
+ return mod_path, array_index
41
+
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,9 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Query
4
+
5
+ class AndFilter < SingleBoolFilter; end
6
+
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Query
4
+
5
+ class BoolFilter < BoolQuery
6
+ plugin AbstractFilter
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,67 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Query
4
+
5
+ class BoolQuery < AbstractQuery
6
+
7
+ many :musts, :class_name => 'MmEsSearch::Api::Query::AbstractQuery'
8
+ many :shoulds, :class_name => 'MmEsSearch::Api::Query::AbstractQuery'
9
+ many :must_nots, :class_name => 'MmEsSearch::Api::Query::AbstractQuery'
10
+ key :boost, Float
11
+ key :minimum_number_should_match, Integer
12
+
13
+ def validate
14
+ raise "cannot have a must_not by itself in a BoolQuery" if (musts.empty? and shoulds.empty? and not self.is_a?(BoolFilter))
15
+ end
16
+
17
+ def to_mongo_query(options = {})
18
+
19
+ validate
20
+
21
+ negated_options = options.merge({:negated => !options[:negated]})
22
+
23
+ and_array = musts.map {|query| query.to_mongo_query(options)} + must_nots.map {|query| query.to_mongo_query(negated_options)}
24
+ or_array = shoulds.map {|query| query.to_mongo_query(options)}
25
+
26
+ bool_params = {}
27
+ bool_params.merge!({'$and' => and_array}) unless and_array.empty?
28
+ bool_params.merge!({'$or' => or_array}) unless or_array.empty?
29
+
30
+ return bool_params
31
+
32
+ end
33
+
34
+ def to_es_query
35
+
36
+ validate
37
+
38
+ # use more optimal and, or, not SingleBoolFilter if appropriate
39
+ if self.is_a?(BoolFilter)
40
+ if (shoulds + must_nots).empty? and not musts.empty? and boost.nil?
41
+ return AndFilter.new(:filters => musts).to_es_query
42
+ elsif (musts + must_nots).empty? and not shoulds.empty? and boost.nil? and minimum_number_should_match == 1
43
+ return OrFilter.new(:filters => shoulds).to_es_query
44
+ elsif (musts + shoulds).empty? and not must_nots.empty? and boost.nil?
45
+ return NotFilter.new(:filters => must_nots).to_es_query
46
+ end
47
+ end
48
+
49
+ must_array = musts.map {|query| query.to_es_query}
50
+ should_array = shoulds.map {|query| query.to_es_query}
51
+ must_not_array = must_nots.map {|query| query.to_es_query}
52
+
53
+ bool_params = {}
54
+ bool_params.merge!({:must => must_array}) unless must_array.empty?
55
+ bool_params.merge!({:should => should_array}) unless should_array.empty?
56
+ bool_params.merge!({:must_not => must_not_array}) unless must_not_array.empty?
57
+ bool_params.merge!({:boost => boost}) unless boost.nil?
58
+ bool_params.merge!({:minimum_number_should_match => minimum_number_should_match}) if minimum_number_should_match?
59
+ return {:bool => bool_params}
60
+
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,31 @@
1
+ module MmEsSearch
2
+ module Api
3
+ module Query
4
+
5
+ class ConstantScoreQuery < AbstractQuery
6
+
7
+ one :query, :class_name => 'MmEsSearch::Api::Query::AbstractQuery'
8
+ key :boost, Integer
9
+
10
+ def to_mongo_query(options = {})
11
+
12
+ return query.to_mongo_query(options)
13
+
14
+ end
15
+
16
+ def to_es_query
17
+
18
+ constant_score_params = {
19
+ :query => query.to_es_query
20
+ }
21
+ constant_score_params.merge!(:boost => boost) if boost?
22
+
23
+ return {:constant_score => constant_score_params}
24
+
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+ end
31
+ end