Skip to content

Commit f852bc5

Browse files
committed
[STORE] [MODEL] Address performance of HashWrapper in Response objects (elastic#825)
* [STORE] Lazily wrap response in HashWrapper and provide #raw_response access * [MODEL] Lazily wrap response in HashWrapper and provide #raw_response access * [MODEL] Opimitize response changes * [STORE] Opimitize response changes
1 parent aa97dc0 commit f852bc5

File tree

5 files changed

+49
-20
lines changed

5 files changed

+49
-20
lines changed

elasticsearch-model/lib/elasticsearch/model/response.rb

+11-10
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ module Response
1010
# Implements Enumerable and forwards its methods to the {#results} object.
1111
#
1212
class Response
13-
attr_reader :klass, :search, :response,
14-
:took, :timed_out, :shards
13+
attr_reader :klass, :search
1514

1615
include Enumerable
1716

@@ -27,9 +26,7 @@ def initialize(klass, search, options={})
2726
# @return [Hash]
2827
#
2928
def response
30-
@response ||= begin
31-
HashWrapper.new(search.execute!)
32-
end
29+
@response ||= HashWrapper.new(search.execute!)
3330
end
3431

3532
# Returns the collection of "hits" from Elasticsearch
@@ -51,31 +48,35 @@ def records(options = {})
5148
# Returns the "took" time
5249
#
5350
def took
54-
response['took']
51+
raw_response['took']
5552
end
5653

5754
# Returns whether the response timed out
5855
#
5956
def timed_out
60-
response['timed_out']
57+
raw_response['timed_out']
6158
end
6259

6360
# Returns the statistics on shards
6461
#
6562
def shards
66-
HashWrapper.new(response['_shards'])
63+
@shards ||= HashWrapper.new(raw_response['_shards'])
6764
end
6865

6966
# Returns a Hashie::Mash of the aggregations
7067
#
7168
def aggregations
72-
Aggregations.new(response['aggregations'])
69+
@aggregations ||= Aggregations.new(raw_response['aggregations'])
7370
end
7471

7572
# Returns a Hashie::Mash of the suggestions
7673
#
7774
def suggestions
78-
Suggestions.new(response['suggest'])
75+
@suggestions ||= Suggestions.new(raw_response['suggest'])
76+
end
77+
78+
def raw_response
79+
@raw_response ||= search.execute!
7980
end
8081
end
8182
end

elasticsearch-model/lib/elasticsearch/model/response/base.rb

+3-2
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@ module Response
44
# Common funtionality for classes in the {Elasticsearch::Model::Response} module
55
#
66
module Base
7-
attr_reader :klass, :response
7+
attr_reader :klass, :response, :raw_response
88

99
# @param klass [Class] The name of the model class
1010
# @param response [Hash] The full response returned from Elasticsearch client
1111
# @param options [Hash] Optional parameters
1212
#
1313
def initialize(klass, response, options={})
1414
@klass = klass
15-
@response = response
15+
@raw_response = response
16+
@response = response
1617
end
1718

1819
# @abstract Implement this method in specific class

elasticsearch-model/test/unit/response_results_test.rb

+3
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,8 @@ def self.document_type; 'bar'; end
2727
assert_equal 'bar', @results.first.foo
2828
end
2929

30+
should "provide access to the raw response" do
31+
assert_equal RESPONSE, @response.raw_response
32+
end
3033
end
3134
end

elasticsearch-persistence/lib/elasticsearch/persistence/repository/response/results.rb

+9-8
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class Results
1111
include Enumerable
1212

1313
attr_reader :repository
14+
attr_reader :raw_response
1415

1516
# The key for accessing the results in an Elasticsearch query response.
1617
#
@@ -30,8 +31,8 @@ class Results
3031
#
3132
def initialize(repository, response, options={})
3233
@repository = repository
33-
@response = Elasticsearch::Model::HashWrapper.new(response)
34-
@options = options
34+
@raw_response = response
35+
@options = options
3536
end
3637

3738
def method_missing(method_name, *arguments, &block)
@@ -45,25 +46,25 @@ def respond_to?(method_name, include_private = false)
4546
# The number of total hits for a query
4647
#
4748
def total
48-
response[HITS][TOTAL]
49+
raw_response[HITS][TOTAL]
4950
end
5051

5152
# The maximum score for a query
5253
#
5354
def max_score
54-
response[HITS][MAX_SCORE]
55+
raw_response[HITS][MAX_SCORE]
5556
end
5657

5758
# Yields [object, hit] pairs to the block
5859
#
5960
def each_with_hit(&block)
60-
results.zip(response[HITS][HITS]).each(&block)
61+
results.zip(raw_response[HITS][HITS]).each(&block)
6162
end
6263

6364
# Yields [object, hit] pairs and returns the result
6465
#
6566
def map_with_hit(&block)
66-
results.zip(response[HITS][HITS]).map(&block)
67+
results.zip(raw_response[HITS][HITS]).map(&block)
6768
end
6869

6970
# Return the collection of domain objects
@@ -76,7 +77,7 @@ def map_with_hit(&block)
7677
# @return [Array]
7778
#
7879
def results
79-
@results ||= response[HITS][HITS].map do |document|
80+
@results ||= raw_response[HITS][HITS].map do |document|
8081
repository.deserialize(document.to_hash)
8182
end
8283
end
@@ -93,7 +94,7 @@ def results
9394
# @return [Elasticsearch::Model::HashWrapper]
9495
#
9596
def response
96-
@response
97+
@response ||= Elasticsearch::Model::HashWrapper.new(raw_response)
9798
end
9899
end
99100
end

elasticsearch-persistence/spec/repository/response/results_spec.rb

+23
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,22 @@ def deserialize(document)
6666
it 'wraps the response in a HashWrapper' do
6767
expect(results.response._shards.total).to eq(5)
6868
end
69+
70+
context 'when the response method is not called' do
71+
72+
it 'does not create an instance of HashWrapper' do
73+
expect(Elasticsearch::Model::HashWrapper).not_to receive(:new)
74+
results
75+
end
76+
end
77+
78+
context 'when the response method is called' do
79+
80+
it 'does create an instance of HashWrapper' do
81+
expect(Elasticsearch::Model::HashWrapper).to receive(:new)
82+
results.response
83+
end
84+
end
6985
end
7086

7187
describe '#total' do
@@ -102,4 +118,11 @@ def deserialize(document)
102118
expect(results.map_with_hit { |pair| pair[0] }).to eq(['Object', 'Object'])
103119
end
104120
end
121+
122+
describe '#raw_response' do
123+
124+
it 'returns the raw response from Elasticsearch' do
125+
expect(results.raw_response).to eq(response)
126+
end
127+
end
105128
end

0 commit comments

Comments
 (0)