@@ -2,125 +2,106 @@ module Elasticsearch
2
2
module Model
3
3
module Adapter
4
4
5
- # An adapter to be used for deserializing results from multiple models, retrieved through
6
- # Elasticsearch::Model.search
5
+ # An adapter to be used for deserializing results from multiple models,
6
+ # retrieved through ` Elasticsearch::Model.search`
7
7
#
8
8
# @see Elasticsearch::Model.search
9
9
#
10
10
module Multiple
11
-
12
11
Adapter . register self , lambda { |klass | klass . is_a? Multimodel }
13
12
14
13
module Records
15
-
16
- # Returns an Array, which elements are the model instances represented
17
- # by the search results.
18
- #
19
- # This means that if the models queried are a Mixture of ActiveRecord, Mongoid, or
20
- # POROs, the elements contained in this array will also be instances of those models
21
- #
22
- # Ranking of results across multiple indexes is preserved, and queries made to the different
23
- # model's datasources are minimal.
24
- #
25
- # Internally, it gets the results, as ranked by elasticsearch.
26
- # Then results are grouped by _type
27
- # Then the model corresponding to each _type is queried to retrieve the records
28
- # Finally records are rearranged in the same way results were ranked.
14
+ # Returns a collection of model instances, possibly of different classes (ActiveRecord, Mongoid, ...)
29
15
#
30
- # @return [ElasticSearch::Model]
16
+ # @note The order of results in the Elasticsearch response is preserved
31
17
#
32
18
def records
33
- @_records ||= begin
34
- result = [ ]
35
- by_type = __records_by_type
36
- __hits . each do |hit |
37
- result << by_type [ __type ( hit ) ] [ hit [ :_id ] ]
38
- end
39
- result . compact
19
+ records_by_type = __records_by_type
20
+
21
+ response . response [ "hits" ] [ "hits" ] . map do |hit |
22
+ records_by_type [ __type_for_hit ( hit ) ] [ hit [ :_id ] ]
40
23
end
41
24
end
42
25
43
- # Returns the record representation of the results retrieved from Elasticsearch, grouped
44
- # by model type
26
+ # Returns the collection of records grouped by class based on `_type`
45
27
#
46
- # @example
47
- # {Series =>
48
- # {"1"=> #<Series id: 1, series_name: "The Who S01", created_at: "2015-02-23 17:18:28">},
28
+ # Example:
49
29
#
50
- # "Title =>
51
- # {"1"=> #<Title id: 1, name: "Who Strikes Back", created_at: "2015-02-23 17:18:28">}}
30
+ # {
31
+ # Foo => {"1"=> #<Foo id: 1, title: "ABC"}, ...},
32
+ # Bar => {"1"=> #<Bar id: 1, name: "XYZ"}, ...}
33
+ # }
52
34
#
53
35
# @api private
54
36
#
55
37
def __records_by_type
56
- array = __ids_by_type . map do |klass , ids |
57
- records = __type_records ( klass , ids )
58
- ids = records . map ( &:id ) . map ( &:to_s )
59
- [ klass , Hash [ ids . zip ( records ) ] ]
38
+ result = __ids_by_type . map do |klass , ids |
39
+ records = __records_for_klass ( klass , ids )
40
+ ids = records . map ( &:id ) . map ( &:to_s )
41
+ [ klass , Hash [ ids . zip ( records ) ] ]
60
42
end
61
- Hash [ array ]
43
+
44
+ Hash [ result ]
62
45
end
63
46
64
- # Returns the records for a specific type
47
+ # Returns the collection of records for a specific type based on passed `klass`
65
48
#
66
49
# @api private
67
50
#
68
- def __type_records ( klass , ids )
69
- if ( adapter = Adapter . adapters [ ActiveRecord ] ) && adapter . call ( klass )
70
- klass . where ( klass . primary_key => ids )
71
- elsif ( adapter = Adapter . adapters [ Mongoid ] ) && adapter . call ( klass )
72
- klass . where ( :id . in => ids )
73
- else
74
- klass . find ( ids )
51
+ def __records_for_klass ( klass , ids )
52
+ adapter = __adapter_name_for_klass ( klass )
53
+
54
+ case adapter
55
+ when Elasticsearch ::Model ::Adapter ::ActiveRecord
56
+ klass . where ( klass . primary_key => ids )
57
+ when Elasticsearch ::Model ::Adapter ::Mongoid
58
+ klass . where ( :id . in => ids )
59
+ else
60
+ klass . find ( ids )
75
61
end
76
62
end
77
63
78
-
79
- # @return A Hash containing for each type, the ids to retrieve
64
+ # Returns the record IDs grouped by class based on type `_type`
65
+ #
66
+ # Example:
80
67
#
81
- # @example {Series => ["1"], Title =>["1", "5"]}
68
+ # { Foo => ["1"], Bar => ["1", "5"] }
82
69
#
83
70
# @api private
84
71
#
85
72
def __ids_by_type
86
73
ids_by_type = { }
87
- __hits . each do |hit |
88
- type = __type ( hit )
74
+
75
+ response . response [ "hits" ] [ "hits" ] . each do |hit |
76
+ type = __type_for_hit ( hit )
89
77
ids_by_type [ type ] ||= [ ]
90
78
ids_by_type [ type ] << hit [ :_id ]
91
79
end
92
80
ids_by_type
93
81
end
94
82
95
- # Returns the class of the model associated to a certain hit
96
- #
97
- # A simple class-level memoization over the `_index` and `_type` properties of the hit is applied.
98
- # Hence querying the Model Registry is done the minimal amount of times.
99
- #
100
- # Event though memoization happens at the class level, the side effect of a race condition will only be
101
- # to iterate over models one extra time, so we can consider the method thread-safe, and don't include
102
- # any Mutex.synchronize around the method implementaion
83
+ # Returns the class of the model corresponding to a specific `hit` in Elasticsearch results
103
84
#
104
85
# @see Elasticsearch::Model::Registry
105
86
#
106
- # @return Class
107
- #
108
87
# @api private
109
88
#
110
- def __type ( hit )
89
+ def __type_for_hit ( hit )
111
90
@@__types ||= { }
112
- @@__types [ [ hit [ :_index ] , hit [ :_type ] ] . join ( "::" ) ] ||= begin
113
- Registry . all . detect { |model | model . index_name == hit [ :_index ] && model . document_type == hit [ :_type ] }
91
+
92
+ @@__types [ "#{ hit [ :_index ] } ::#{ hit [ :_type ] } " ] ||= begin
93
+ Registry . all . detect do |model |
94
+ model . index_name == hit [ :_index ] && model . document_type == hit [ :_type ]
95
+ end
114
96
end
115
97
end
116
98
117
-
118
- # Memoizes and returns the hits from the response
99
+ # Returns the adapter registered for a particular `klass` or `nil` if not available
119
100
#
120
101
# @api private
121
102
#
122
- def __hits
123
- @__hits ||= response . response [ "hits" ] [ "hits" ]
103
+ def __adapter_name_for_klass ( klass )
104
+ Adapter . adapters . select { | name , checker | checker . call ( klass ) } . keys . first
124
105
end
125
106
end
126
107
end
0 commit comments