datastax_rails 1.0.14.10 → 1.0.15
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/datastax_rails/grouped_collection.rb +9 -0
- data/lib/datastax_rails/relation/search_methods.rb +20 -5
- data/lib/datastax_rails/relation.rb +42 -15
- data/lib/datastax_rails/tasks/column_family.rb +1 -0
- data/lib/datastax_rails/version.rb +1 -1
- data/lib/datastax_rails.rb +1 -0
- data/spec/datastax_rails/cql/update_spec.rb +1 -1
- data/spec/datastax_rails/relation_spec.rb +28 -0
- data/spec/dummy/log/test.log +1943 -0
- metadata +5 -5
@@ -96,15 +96,30 @@ module DatastaxRails
|
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
|
-
# Group results by
|
100
|
-
# for each group.
|
99
|
+
# Group results by a given attribute only returning the top results
|
100
|
+
# for each group. In Lucene, this is often referred to as Field Collapsing.
|
101
|
+
#
|
102
|
+
# This modifies the behavior of pagination. When using a group, +per_page+ will
|
103
|
+
# specify the number of results returned *for each group*. In addition, +page+
|
104
|
+
# will move all groups forward by one page possibly resulting in some groups
|
105
|
+
# getting dropped off if they have fewer matching entires than others.
|
106
|
+
#
|
107
|
+
# When grouping is being used, the sort values will be used to sort results within
|
108
|
+
# a given group. Any sorting of the groups themselves will need to be handled
|
109
|
+
# after-the-fact as the groups are returned as hash of Collection objects.
|
110
|
+
#
|
111
|
+
# Because SOLR is doing the grouping work, we can only group on single-valued
|
112
|
+
# fields (i.e., not +text+ or +array+ attributes). In the future, SOLR may
|
113
|
+
# support grouping on multi-valued fields.
|
114
|
+
#
|
115
|
+
# NOTE: Group names will be lower-cased
|
101
116
|
#
|
102
117
|
# Model.group(:program_id)
|
103
|
-
def group(
|
104
|
-
return self if
|
118
|
+
def group(attribute)
|
119
|
+
return self if attribute.blank?
|
105
120
|
|
106
121
|
clone.tap do |r|
|
107
|
-
r.
|
122
|
+
r.group_value = attribute
|
108
123
|
end
|
109
124
|
end
|
110
125
|
|
@@ -2,8 +2,8 @@ require 'rsolr'
|
|
2
2
|
|
3
3
|
module DatastaxRails
|
4
4
|
class Relation
|
5
|
-
MULTI_VALUE_METHODS = [:
|
6
|
-
SINGLE_VALUE_METHODS = [:page, :per_page, :reverse_order, :query_parser, :consistency, :ttl, :use_solr, :escape]
|
5
|
+
MULTI_VALUE_METHODS = [:order, :where, :where_not, :fulltext, :greater_than, :less_than, :select]
|
6
|
+
SINGLE_VALUE_METHODS = [:page, :per_page, :reverse_order, :query_parser, :consistency, :ttl, :use_solr, :escape, :group]
|
7
7
|
|
8
8
|
SOLR_CHAR_RX = /([\+\!\(\)\[\]\^\"\~\:\'\=]+)/
|
9
9
|
|
@@ -74,6 +74,9 @@ module DatastaxRails
|
|
74
74
|
# If the relation has not been populated yet, a limit of 1 will be
|
75
75
|
# placed on the query before it is executed.
|
76
76
|
#
|
77
|
+
# For a grouped query, this still returns the total number of
|
78
|
+
# matching documents
|
79
|
+
#
|
77
80
|
# Compare with #size.
|
78
81
|
#
|
79
82
|
# XXX: Count via CQL is useless unless criteria has been applied.
|
@@ -164,9 +167,12 @@ module DatastaxRails
|
|
164
167
|
# the number of results in the current page. DatastaxRails models
|
165
168
|
# can have a +default_page_size+ set which will cause them to be
|
166
169
|
# paginated all the time.
|
170
|
+
#
|
171
|
+
# For a grouped query, this returns the size of the largest group.
|
172
|
+
#
|
167
173
|
# Compare with #count
|
168
174
|
def size
|
169
|
-
return @results.size if loaded?
|
175
|
+
return @results.size if loaded? && !@group_value
|
170
176
|
total_entries = count
|
171
177
|
(per_page_value && total_entries > per_page_value) ? per_page_value : total_entries
|
172
178
|
end
|
@@ -184,7 +190,7 @@ module DatastaxRails
|
|
184
190
|
return @results if loaded?
|
185
191
|
if use_solr_value
|
186
192
|
@results = query_via_solr
|
187
|
-
@count = @results.total_entries
|
193
|
+
@count = @group_value ? @results.total_for_all : @results.total_entries
|
188
194
|
else
|
189
195
|
@results = query_via_cql
|
190
196
|
end
|
@@ -245,7 +251,8 @@ module DatastaxRails
|
|
245
251
|
# Runs the query with a limit of 1 just to grab the total results attribute off
|
246
252
|
# the result set.
|
247
253
|
def count_via_solr
|
248
|
-
limit(1).select(:id).to_a
|
254
|
+
results = limit(1).select(:id).to_a
|
255
|
+
@group_value ? results.total_for_all : results.total_entries
|
249
256
|
end
|
250
257
|
|
251
258
|
# Escapes values that might otherwise mess up the URL or confuse SOLR.
|
@@ -325,24 +332,44 @@ module DatastaxRails
|
|
325
332
|
|
326
333
|
select_columns = select_values.empty? ? (@klass.attribute_definitions.keys - @klass.lazy_attributes) : select_values.flatten
|
327
334
|
|
328
|
-
|
329
|
-
|
335
|
+
if(@group_value)
|
336
|
+
results = DatastaxRails::GroupedCollection.new
|
337
|
+
params[:group] = 'true'
|
338
|
+
params['group.field'] = @group_value
|
339
|
+
params['group.limit'] = @per_page_value
|
340
|
+
params['group.offset'] = (@page_value - 1) * @per_page_value
|
341
|
+
params['group.ngroups'] = 'true'
|
342
|
+
response = rsolr.post('select', :params => params)["grouped"][@group_value.to_s]
|
343
|
+
results.total_groups = response['ngroups'].to_i
|
344
|
+
results.total_for_all = response['matches'].to_i
|
345
|
+
results.total_entries = 0
|
346
|
+
response['groups'].each do |group|
|
347
|
+
results[group['groupValue']] = parse_docs(group['doclist'], select_columns)
|
348
|
+
results.total_entries = results[group['groupValue']].total_entries if results[group['groupValue']].total_entries > results.total_entries
|
349
|
+
end
|
350
|
+
else
|
351
|
+
response = rsolr.paginate(@page_value, @per_page_value, 'select', :params => params)["response"]
|
352
|
+
results = parse_docs(response, select_columns)
|
353
|
+
end
|
354
|
+
results
|
355
|
+
end
|
356
|
+
|
357
|
+
|
358
|
+
def parse_docs(response, select_columns)
|
330
359
|
results = DatastaxRails::Collection.new
|
331
360
|
results.total_entries = response['numFound'].to_i
|
332
|
-
|
333
|
-
|
334
|
-
|
361
|
+
response['docs'].each do |doc|
|
362
|
+
id = doc['id']
|
363
|
+
if(@consistency_value)
|
335
364
|
obj = @klass.with_cassandra.consistency(@consistency_value).find_by_id(id)
|
336
365
|
results << obj if obj
|
337
|
-
|
338
|
-
|
339
|
-
response['docs'].each do |doc|
|
340
|
-
key = doc.delete('id')
|
341
|
-
results << @klass.instantiate(key,doc, select_columns)
|
366
|
+
else
|
367
|
+
results << @klass.instantiate(id, doc, select_columns)
|
342
368
|
end
|
343
369
|
end
|
344
370
|
results
|
345
371
|
end
|
372
|
+
protected(:parse_docs)
|
346
373
|
|
347
374
|
def inspect(just_me = false)
|
348
375
|
just_me ? super() : to_a.inspect
|
@@ -109,6 +109,7 @@ module DatastaxRails
|
|
109
109
|
solr_url = "#{DatastaxRails::Base.solr_base_url}/resource/#{DatastaxRails::Base.config[:keyspace]}.#{model.column_family}"
|
110
110
|
uri = URI.parse(solr_url)
|
111
111
|
Net::HTTP.start(uri.host, uri.port) do |http|
|
112
|
+
http.read_timeout(300)
|
112
113
|
if force || solrconfig_digest != sm_digests['solrconfig']
|
113
114
|
puts "Posting Solr Config file to '#{solr_url}/solrconfig.xml'"
|
114
115
|
http.post(uri.path+"/solrconfig.xml", solrconfig)
|
data/lib/datastax_rails.rb
CHANGED
@@ -8,7 +8,7 @@ describe DatastaxRails::Cql::Update do
|
|
8
8
|
it "should generate valid CQL" do
|
9
9
|
cql = DatastaxRails::Cql::Update.new(@model_class, "12345")
|
10
10
|
cql.using(DatastaxRails::Cql::Consistency::QUORUM).columns(:name => 'John', :age => '23')
|
11
|
-
cql.to_cql.should
|
11
|
+
cql.to_cql.should match(/update users using consistency QUORUM SET (name = 'John', age = '23'|age = '23', name = 'John') WHERE KEY IN \('12345'\)/)
|
12
12
|
end
|
13
13
|
|
14
14
|
it_has_behavior "default_consistency"
|
@@ -127,4 +127,32 @@ describe DatastaxRails::Relation do
|
|
127
127
|
relation.total_pages.should == 4
|
128
128
|
end
|
129
129
|
end
|
130
|
+
|
131
|
+
describe "grouped queries" do
|
132
|
+
before(:each) do
|
133
|
+
Person.create(:name => 'John', :nickname => 'J')
|
134
|
+
Person.create(:name => 'Jason', :nickname => 'J')
|
135
|
+
Person.create(:name => 'James', :nickname => 'J')
|
136
|
+
Person.create(:name => 'Kathrine', :nickname => 'Kat')
|
137
|
+
Person.create(:name => 'Kathy', :nickname => 'Kat')
|
138
|
+
Person.create(:name => 'Steven', :nickname => 'Steve')
|
139
|
+
Person.commit_solr
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should return matching documents grouped by an attribute" do
|
143
|
+
results = Person.group(:nickname).all
|
144
|
+
results['j'].should have(3).items
|
145
|
+
results['kat'].should have(2).items
|
146
|
+
results['steve'].should have(1).item
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should return total_entires as the highest value of any group" do
|
150
|
+
results = Person.group(:nickname).all
|
151
|
+
results.total_entries.should eq(3)
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should still return a total count when using the count method" do
|
155
|
+
results = Person.group(:nickname).count.should eq(6)
|
156
|
+
end
|
157
|
+
end
|
130
158
|
end
|