elasticsearch-model-queryable 0.1.5
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/.gitignore +20 -0
- data/CHANGELOG.md +26 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +13 -0
- data/README.md +695 -0
- data/Rakefile +59 -0
- data/elasticsearch-model.gemspec +57 -0
- data/examples/activerecord_article.rb +77 -0
- data/examples/activerecord_associations.rb +162 -0
- data/examples/couchbase_article.rb +66 -0
- data/examples/datamapper_article.rb +71 -0
- data/examples/mongoid_article.rb +68 -0
- data/examples/ohm_article.rb +70 -0
- data/examples/riak_article.rb +52 -0
- data/gemfiles/3.0.gemfile +12 -0
- data/gemfiles/4.0.gemfile +11 -0
- data/lib/elasticsearch/model/adapter.rb +145 -0
- data/lib/elasticsearch/model/adapters/active_record.rb +104 -0
- data/lib/elasticsearch/model/adapters/default.rb +50 -0
- data/lib/elasticsearch/model/adapters/mongoid.rb +92 -0
- data/lib/elasticsearch/model/callbacks.rb +35 -0
- data/lib/elasticsearch/model/client.rb +61 -0
- data/lib/elasticsearch/model/ext/active_record.rb +14 -0
- data/lib/elasticsearch/model/hash_wrapper.rb +15 -0
- data/lib/elasticsearch/model/importing.rb +144 -0
- data/lib/elasticsearch/model/indexing.rb +472 -0
- data/lib/elasticsearch/model/naming.rb +101 -0
- data/lib/elasticsearch/model/proxy.rb +127 -0
- data/lib/elasticsearch/model/response/base.rb +44 -0
- data/lib/elasticsearch/model/response/pagination.rb +173 -0
- data/lib/elasticsearch/model/response/records.rb +69 -0
- data/lib/elasticsearch/model/response/result.rb +63 -0
- data/lib/elasticsearch/model/response/results.rb +31 -0
- data/lib/elasticsearch/model/response.rb +71 -0
- data/lib/elasticsearch/model/searching.rb +107 -0
- data/lib/elasticsearch/model/serializing.rb +35 -0
- data/lib/elasticsearch/model/version.rb +5 -0
- data/lib/elasticsearch/model.rb +157 -0
- data/test/integration/active_record_associations_parent_child.rb +139 -0
- data/test/integration/active_record_associations_test.rb +307 -0
- data/test/integration/active_record_basic_test.rb +179 -0
- data/test/integration/active_record_custom_serialization_test.rb +62 -0
- data/test/integration/active_record_import_test.rb +100 -0
- data/test/integration/active_record_namespaced_model_test.rb +49 -0
- data/test/integration/active_record_pagination_test.rb +132 -0
- data/test/integration/mongoid_basic_test.rb +193 -0
- data/test/test_helper.rb +63 -0
- data/test/unit/adapter_active_record_test.rb +140 -0
- data/test/unit/adapter_default_test.rb +41 -0
- data/test/unit/adapter_mongoid_test.rb +102 -0
- data/test/unit/adapter_test.rb +69 -0
- data/test/unit/callbacks_test.rb +31 -0
- data/test/unit/client_test.rb +27 -0
- data/test/unit/importing_test.rb +176 -0
- data/test/unit/indexing_test.rb +478 -0
- data/test/unit/module_test.rb +57 -0
- data/test/unit/naming_test.rb +76 -0
- data/test/unit/proxy_test.rb +89 -0
- data/test/unit/response_base_test.rb +40 -0
- data/test/unit/response_pagination_kaminari_test.rb +189 -0
- data/test/unit/response_pagination_will_paginate_test.rb +208 -0
- data/test/unit/response_records_test.rb +91 -0
- data/test/unit/response_result_test.rb +90 -0
- data/test/unit/response_results_test.rb +31 -0
- data/test/unit/response_test.rb +67 -0
- data/test/unit/searching_search_request_test.rb +78 -0
- data/test/unit/searching_test.rb +41 -0
- data/test/unit/serializing_test.rb +17 -0
- metadata +466 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
module Elasticsearch
|
2
|
+
module Model
|
3
|
+
module Response
|
4
|
+
# Common funtionality for classes in the {Elasticsearch::Model::Response} module
|
5
|
+
#
|
6
|
+
module Base
|
7
|
+
attr_reader :klass, :response
|
8
|
+
|
9
|
+
# @param klass [Class] The name of the model class
|
10
|
+
# @param response [Hash] The full response returned from Elasticsearch client
|
11
|
+
# @param options [Hash] Optional parameters
|
12
|
+
#
|
13
|
+
def initialize(klass, response, options={})
|
14
|
+
@klass = klass
|
15
|
+
@response = response
|
16
|
+
end
|
17
|
+
|
18
|
+
# @abstract Implement this method in specific class
|
19
|
+
#
|
20
|
+
def results
|
21
|
+
raise NotImplemented, "Implement this method in #{klass}"
|
22
|
+
end
|
23
|
+
|
24
|
+
# @abstract Implement this method in specific class
|
25
|
+
#
|
26
|
+
def records
|
27
|
+
raise NotImplemented, "Implement this method in #{klass}"
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns the total number of hits
|
31
|
+
#
|
32
|
+
def total
|
33
|
+
response.response['hits']['total']
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns the max_score
|
37
|
+
#
|
38
|
+
def max_score
|
39
|
+
response.response['hits']['max_score']
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
module Elasticsearch
|
2
|
+
module Model
|
3
|
+
module Response
|
4
|
+
|
5
|
+
# Pagination for search results/records
|
6
|
+
#
|
7
|
+
module Pagination
|
8
|
+
# Allow models to be paginated with the "kaminari" gem [https://github.com/amatsuda/kaminari]
|
9
|
+
#
|
10
|
+
module Kaminari
|
11
|
+
def self.included(base)
|
12
|
+
# Include the Kaminari configuration and paging method in response
|
13
|
+
#
|
14
|
+
base.__send__ :include, ::Kaminari::ConfigurationMethods::ClassMethods
|
15
|
+
base.__send__ :include, ::Kaminari::PageScopeMethods
|
16
|
+
|
17
|
+
# Include the Kaminari paging methods in results and records
|
18
|
+
#
|
19
|
+
Elasticsearch::Model::Response::Results.__send__ :include, ::Kaminari::ConfigurationMethods::ClassMethods
|
20
|
+
Elasticsearch::Model::Response::Results.__send__ :include, ::Kaminari::PageScopeMethods
|
21
|
+
Elasticsearch::Model::Response::Records.__send__ :include, ::Kaminari::PageScopeMethods
|
22
|
+
|
23
|
+
Elasticsearch::Model::Response::Results.__send__ :delegate, :limit_value, :offset_value, :total_count, to: :response
|
24
|
+
Elasticsearch::Model::Response::Records.__send__ :delegate, :limit_value, :offset_value, :total_count, to: :response
|
25
|
+
|
26
|
+
base.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
27
|
+
# Define the `page` Kaminari method
|
28
|
+
#
|
29
|
+
def #{::Kaminari.config.page_method_name}(num=nil)
|
30
|
+
@results = nil
|
31
|
+
@records = nil
|
32
|
+
@response = nil
|
33
|
+
@page = [num.to_i, 1].max
|
34
|
+
@per_page ||= klass.default_per_page
|
35
|
+
|
36
|
+
self.search.definition.update size: @per_page,
|
37
|
+
from: @per_page * (@page - 1)
|
38
|
+
|
39
|
+
self
|
40
|
+
end
|
41
|
+
RUBY
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns the current "limit" (`size`) value
|
45
|
+
#
|
46
|
+
def limit_value
|
47
|
+
case
|
48
|
+
when search.definition[:size]
|
49
|
+
search.definition[:size]
|
50
|
+
else
|
51
|
+
search.klass.default_per_page
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns the current "offset" (`from`) value
|
56
|
+
#
|
57
|
+
def offset_value
|
58
|
+
case
|
59
|
+
when search.definition[:from]
|
60
|
+
search.definition[:from]
|
61
|
+
else
|
62
|
+
0
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Set the "limit" (`size`) value
|
67
|
+
#
|
68
|
+
def limit(value)
|
69
|
+
@results = nil
|
70
|
+
@records = nil
|
71
|
+
@response = nil
|
72
|
+
@per_page = value
|
73
|
+
|
74
|
+
search.definition.update :size => @per_page
|
75
|
+
search.definition.update :from => @per_page * (@page - 1) if @page
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
# Set the "offset" (`from`) value
|
80
|
+
#
|
81
|
+
def offset(value)
|
82
|
+
@results = nil
|
83
|
+
@records = nil
|
84
|
+
@response = nil
|
85
|
+
@page = nil
|
86
|
+
search.definition.update :from => value
|
87
|
+
self
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns the total number of results
|
91
|
+
#
|
92
|
+
def total_count
|
93
|
+
results.total
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Allow models to be paginated with the "will_paginate" gem [https://github.com/mislav/will_paginate]
|
98
|
+
#
|
99
|
+
module WillPaginate
|
100
|
+
def self.included(base)
|
101
|
+
base.__send__ :include, ::WillPaginate::CollectionMethods
|
102
|
+
|
103
|
+
# Include the paging methods in results and records
|
104
|
+
#
|
105
|
+
methods = [:current_page, :offset, :length, :per_page, :total_entries, :total_pages, :previous_page, :next_page, :out_of_bounds?]
|
106
|
+
Elasticsearch::Model::Response::Results.__send__ :delegate, *methods, to: :response
|
107
|
+
Elasticsearch::Model::Response::Records.__send__ :delegate, *methods, to: :response
|
108
|
+
end
|
109
|
+
|
110
|
+
def offset
|
111
|
+
(current_page - 1) * per_page
|
112
|
+
end
|
113
|
+
|
114
|
+
def length
|
115
|
+
search.definition[:size]
|
116
|
+
end
|
117
|
+
|
118
|
+
# Main pagination method
|
119
|
+
#
|
120
|
+
# @example
|
121
|
+
#
|
122
|
+
# Article.search('foo').paginate(page: 1, per_page: 30)
|
123
|
+
#
|
124
|
+
def paginate(options)
|
125
|
+
page = [options[:page].to_i, 1].max
|
126
|
+
per_page = (options[:per_page] || klass.per_page).to_i
|
127
|
+
|
128
|
+
search.definition.update size: per_page,
|
129
|
+
from: (page - 1) * per_page
|
130
|
+
self
|
131
|
+
end
|
132
|
+
|
133
|
+
# Return the current page
|
134
|
+
#
|
135
|
+
def current_page
|
136
|
+
search.definition[:from] / per_page + 1 if search.definition[:from] && per_page
|
137
|
+
end
|
138
|
+
|
139
|
+
# Pagination method
|
140
|
+
#
|
141
|
+
# @example
|
142
|
+
#
|
143
|
+
# Article.search('foo').page(2)
|
144
|
+
#
|
145
|
+
def page(num)
|
146
|
+
paginate(page: num, per_page: per_page) # shorthand
|
147
|
+
end
|
148
|
+
|
149
|
+
# Return or set the "size" value
|
150
|
+
#
|
151
|
+
# @example
|
152
|
+
#
|
153
|
+
# Article.search('foo').per_page(15).page(2)
|
154
|
+
#
|
155
|
+
def per_page(num = nil)
|
156
|
+
if num.nil?
|
157
|
+
search.definition[:size]
|
158
|
+
else
|
159
|
+
paginate(page: current_page, per_page: num) # shorthand
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# Returns the total number of results
|
164
|
+
#
|
165
|
+
def total_entries
|
166
|
+
results.total
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Elasticsearch
|
2
|
+
module Model
|
3
|
+
module Response
|
4
|
+
|
5
|
+
# Encapsulates the collection of records returned from the database
|
6
|
+
#
|
7
|
+
# Implements Enumerable and forwards its methods to the {#records} object,
|
8
|
+
# which is provided by an {Elasticsearch::Model::Adapter::Adapter} implementation.
|
9
|
+
#
|
10
|
+
class Records
|
11
|
+
include Enumerable
|
12
|
+
|
13
|
+
delegate :each, :empty?, :size, :slice, :[], :to_a, :to_ary, to: :records
|
14
|
+
|
15
|
+
include Base
|
16
|
+
|
17
|
+
# @see Base#initialize
|
18
|
+
#
|
19
|
+
def initialize(klass, response, options = {})
|
20
|
+
super
|
21
|
+
|
22
|
+
# Include module provided by the adapter in the singleton class ("metaclass")
|
23
|
+
#
|
24
|
+
adapter = Adapter.from_class(klass)
|
25
|
+
metaclass = class << self; self; end
|
26
|
+
metaclass.__send__ :include, adapter.records_mixin
|
27
|
+
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the hit IDs
|
32
|
+
#
|
33
|
+
def ids
|
34
|
+
response.response["hits"]["hits"].map { |hit| hit["_id"] }
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns the {Results} collection
|
38
|
+
#
|
39
|
+
def results
|
40
|
+
response.results
|
41
|
+
end
|
42
|
+
|
43
|
+
# Yields [record, hit] pairs to the block
|
44
|
+
#
|
45
|
+
def each_with_hit(&block)
|
46
|
+
records.to_a.zip(results).each(&block)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Yields [record, hit] pairs and returns the result
|
50
|
+
#
|
51
|
+
def map_with_hit(&block)
|
52
|
+
records.to_a.zip(results).map(&block)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Delegate methods to `@records`
|
56
|
+
#
|
57
|
+
def method_missing(method_name, *arguments)
|
58
|
+
records.respond_to?(method_name) ? records.__send__(method_name, *arguments) : super
|
59
|
+
end
|
60
|
+
|
61
|
+
# Respond to methods from `@records`
|
62
|
+
#
|
63
|
+
def respond_to?(method_name, include_private = false)
|
64
|
+
records.respond_to?(method_name) || super
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Elasticsearch
|
2
|
+
module Model
|
3
|
+
module Response
|
4
|
+
|
5
|
+
# Encapsulates the "hit" returned from the Elasticsearch client
|
6
|
+
#
|
7
|
+
# Wraps the raw Hash with in a `Hashie::Mash` instance, providing
|
8
|
+
# access to the Hash properties by calling Ruby methods.
|
9
|
+
#
|
10
|
+
# @see https://github.com/intridea/hashie
|
11
|
+
#
|
12
|
+
class Result
|
13
|
+
|
14
|
+
# @param attributes [Hash] A Hash with document properties
|
15
|
+
#
|
16
|
+
def initialize(attributes={})
|
17
|
+
@result = HashWrapper.new(attributes)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Return document `_id` as `id`
|
21
|
+
#
|
22
|
+
def id
|
23
|
+
@result['_id']
|
24
|
+
end
|
25
|
+
|
26
|
+
# Return document `_type` as `_type`
|
27
|
+
#
|
28
|
+
def type
|
29
|
+
@result['_type']
|
30
|
+
end
|
31
|
+
|
32
|
+
# Delegate methods to `@result` or `@result._source`
|
33
|
+
#
|
34
|
+
def method_missing(name, *arguments)
|
35
|
+
case
|
36
|
+
when name.to_s.end_with?('?')
|
37
|
+
@result.__send__(name, *arguments) || ( @result._source && @result._source.__send__(name, *arguments) )
|
38
|
+
when @result.respond_to?(name)
|
39
|
+
@result.__send__ name, *arguments
|
40
|
+
when @result._source && @result._source.respond_to?(name)
|
41
|
+
@result._source.__send__ name, *arguments
|
42
|
+
else
|
43
|
+
super
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Respond to methods from `@result` or `@result._source`
|
48
|
+
#
|
49
|
+
def respond_to?(method_name, include_private = false)
|
50
|
+
@result.respond_to?(method_name.to_sym) || \
|
51
|
+
@result._source && @result._source.respond_to?(method_name.to_sym) || \
|
52
|
+
super
|
53
|
+
end
|
54
|
+
|
55
|
+
def as_json(options={})
|
56
|
+
@result.as_json(options)
|
57
|
+
end
|
58
|
+
|
59
|
+
# TODO: #to_s, #inspect, with support for Pry
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Elasticsearch
|
2
|
+
module Model
|
3
|
+
module Response
|
4
|
+
|
5
|
+
# Encapsulates the collection of documents returned from Elasticsearch
|
6
|
+
#
|
7
|
+
# Implements Enumerable and forwards its methods to the {#results} object.
|
8
|
+
#
|
9
|
+
class Results
|
10
|
+
include Base
|
11
|
+
include Enumerable
|
12
|
+
|
13
|
+
delegate :each, :empty?, :size, :slice, :[], :to_a, :to_ary, to: :results
|
14
|
+
|
15
|
+
# @see Base#initialize
|
16
|
+
#
|
17
|
+
def initialize(klass, response, options={})
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns the {Results} collection
|
22
|
+
#
|
23
|
+
def results
|
24
|
+
# TODO: Configurable custom wrapper
|
25
|
+
@results = response.response['hits']['hits'].map { |hit| Result.new(hit) }
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Elasticsearch
|
2
|
+
module Model
|
3
|
+
|
4
|
+
# Contains modules and classes for wrapping the response from Elasticsearch
|
5
|
+
#
|
6
|
+
module Response
|
7
|
+
|
8
|
+
# Encapsulate the response returned from the Elasticsearch client
|
9
|
+
#
|
10
|
+
# Implements Enumerable and forwards its methods to the {#results} object.
|
11
|
+
#
|
12
|
+
class Response
|
13
|
+
attr_reader :klass, :search, :response,
|
14
|
+
:took, :timed_out, :shards
|
15
|
+
|
16
|
+
include Enumerable
|
17
|
+
|
18
|
+
delegate :each, :empty?, :size, :slice, :[], :to_ary, to: :results
|
19
|
+
|
20
|
+
def initialize(klass, search, options={})
|
21
|
+
@klass = klass
|
22
|
+
@search = search
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns the Elasticsearch response
|
26
|
+
#
|
27
|
+
# @return [Hash]
|
28
|
+
#
|
29
|
+
def response
|
30
|
+
@response ||= begin
|
31
|
+
HashWrapper.new(search.execute!)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns the collection of "hits" from Elasticsearch
|
36
|
+
#
|
37
|
+
# @return [Results]
|
38
|
+
#
|
39
|
+
def results
|
40
|
+
@results ||= Results.new(klass, self)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns the collection of records from the database
|
44
|
+
#
|
45
|
+
# @return [Records]
|
46
|
+
#
|
47
|
+
def records
|
48
|
+
@records ||= Records.new(klass, self)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns the "took" time
|
52
|
+
#
|
53
|
+
def took
|
54
|
+
response['took']
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns whether the response timed out
|
58
|
+
#
|
59
|
+
def timed_out
|
60
|
+
response['timed_out']
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns the statistics on shards
|
64
|
+
#
|
65
|
+
def shards
|
66
|
+
HashWrapper.new(response['_shards'])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module Elasticsearch
|
2
|
+
module Model
|
3
|
+
|
4
|
+
# Contains functionality related to searching.
|
5
|
+
#
|
6
|
+
module Searching
|
7
|
+
|
8
|
+
# Wraps a search request definition
|
9
|
+
#
|
10
|
+
class SearchRequest
|
11
|
+
attr_reader :klass, :definition
|
12
|
+
|
13
|
+
# @param klass [Class] The class of the model
|
14
|
+
# @param query_or_payload [String,Hash,Object] The search request definition
|
15
|
+
# (string, JSON, Hash, or object responding to `to_hash`)
|
16
|
+
# @param options [Hash] Optional parameters to be passed to the Elasticsearch client
|
17
|
+
#
|
18
|
+
def initialize(klass, query_or_payload, options={})
|
19
|
+
@klass = klass
|
20
|
+
|
21
|
+
__index_name = options[:index] || klass.index_name
|
22
|
+
__document_type = options[:type] || klass.document_type
|
23
|
+
|
24
|
+
case
|
25
|
+
# search query: ...
|
26
|
+
when query_or_payload.respond_to?(:to_hash)
|
27
|
+
body = query_or_payload.to_hash
|
28
|
+
|
29
|
+
# search '{ "query" : ... }'
|
30
|
+
when query_or_payload.is_a?(String) && query_or_payload =~ /^\s*{/
|
31
|
+
body = query_or_payload
|
32
|
+
|
33
|
+
# search '...'
|
34
|
+
else
|
35
|
+
q = query_or_payload
|
36
|
+
end
|
37
|
+
|
38
|
+
if body
|
39
|
+
@definition = { index: __index_name, type: __document_type, body: body }.update options
|
40
|
+
else
|
41
|
+
@definition = { index: __index_name, type: __document_type, q: q }.update options
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Performs the request and returns the response from client
|
46
|
+
#
|
47
|
+
# @return [Hash] The response from Elasticsearch
|
48
|
+
#
|
49
|
+
def execute!
|
50
|
+
klass.client.search(@definition)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
module ClassMethods
|
55
|
+
|
56
|
+
# Provides a `search` method for the model to easily search within an index/type
|
57
|
+
# corresponding to the model settings.
|
58
|
+
#
|
59
|
+
# @param query_or_payload [String,Hash,Object] The search request definition
|
60
|
+
# (string, JSON, Hash, or object responding to `to_hash`)
|
61
|
+
# @param options [Hash] Optional parameters to be passed to the Elasticsearch client
|
62
|
+
#
|
63
|
+
# @return [Elasticsearch::Model::Response::Response]
|
64
|
+
#
|
65
|
+
# @example Simple search in `Article`
|
66
|
+
#
|
67
|
+
# Article.search 'foo'
|
68
|
+
#
|
69
|
+
# @example Search using a search definition as a Hash
|
70
|
+
#
|
71
|
+
# response = Article.search \
|
72
|
+
# query: {
|
73
|
+
# match: {
|
74
|
+
# title: 'foo'
|
75
|
+
# }
|
76
|
+
# },
|
77
|
+
# highlight: {
|
78
|
+
# fields: {
|
79
|
+
# title: {}
|
80
|
+
# }
|
81
|
+
# }
|
82
|
+
#
|
83
|
+
# response.results.first.title
|
84
|
+
# # => "Foo"
|
85
|
+
#
|
86
|
+
# response.results.first.highlight.title
|
87
|
+
# # => ["<em>Foo</em>"]
|
88
|
+
#
|
89
|
+
# response.records.first.title
|
90
|
+
# # Article Load (0.2ms) SELECT "articles".* FROM "articles" WHERE "articles"."id" IN (1, 3)
|
91
|
+
# # => "Foo"
|
92
|
+
#
|
93
|
+
# @example Search using a search definition as a JSON string
|
94
|
+
#
|
95
|
+
# Article.search '{"query" : { "match_all" : {} }}'
|
96
|
+
#
|
97
|
+
def search(query_or_payload, options={})
|
98
|
+
search = SearchRequest.new(self, query_or_payload, options)
|
99
|
+
|
100
|
+
Response::Response.new(self, search)
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Elasticsearch
|
2
|
+
module Model
|
3
|
+
|
4
|
+
# Contains functionality for serializing model instances for the client
|
5
|
+
#
|
6
|
+
module Serializing
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
end
|
10
|
+
|
11
|
+
module InstanceMethods
|
12
|
+
|
13
|
+
# Serialize the record as a Hash, to be passed to the client.
|
14
|
+
#
|
15
|
+
# Re-define this method to customize the serialization.
|
16
|
+
#
|
17
|
+
# @return [Hash]
|
18
|
+
#
|
19
|
+
# @example Return the model instance as a Hash
|
20
|
+
#
|
21
|
+
# Article.first.__elasticsearch__.as_indexed_json
|
22
|
+
# => {"title"=>"Foo"}
|
23
|
+
#
|
24
|
+
# @see Elasticsearch::Model::Indexing
|
25
|
+
#
|
26
|
+
def as_indexed_json(options={})
|
27
|
+
# TODO: Play with the `MyModel.indexes` method -- reject non-mapped attributes, `:as` options, etc
|
28
|
+
self.as_json(options.merge root: false)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|