gojee-sunspot 2.0.4 → 2.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,853 @@
1
+ # Sunspot
2
+
3
+ [![Build Status](https://secure.travis-ci.org/sunspot/sunspot.png)](http://travis-ci.org/sunspot/sunspot)
4
+
5
+ Sunspot is a Ruby library for expressive, powerful interaction with the Solr
6
+ search engine. Sunspot is built on top of the RSolr library, which
7
+ provides a low-level interface for Solr interaction; Sunspot provides a simple,
8
+ intuitive, expressive DSL backed by powerful features for indexing objects and
9
+ searching for them.
10
+
11
+ Sunspot is designed to be easily plugged in to any ORM, or even non-database-backed
12
+ objects such as the filesystem.
13
+
14
+ This README provides a high level overview; class-by-class and
15
+ method-by-method documentation is available in the [API
16
+ reference](http://sunspot.github.com/sunspot/docs/).
17
+
18
+ ## Quickstart with Rails 3
19
+
20
+ Add to Gemfile:
21
+
22
+ ```ruby
23
+ gem 'sunspot_rails'
24
+ gem 'sunspot_solr' # optional pre-packaged Solr distribution for use in development
25
+ ```
26
+
27
+ Bundle it!
28
+
29
+ ```bash
30
+ bundle install
31
+ ```
32
+
33
+ Generate a default configuration file:
34
+
35
+ ```bash
36
+ rails generate sunspot_rails:install
37
+ ```
38
+
39
+ If `sunspot_solr` was installed, start the packaged Solr distribution
40
+ with:
41
+
42
+ ```bash
43
+ bundle exec rake sunspot:solr:start # or sunspot:solr:run to start in foreground
44
+ ```
45
+
46
+ ## Setting Up Objects
47
+
48
+ Add a `searchable` block to the objects you wish to index.
49
+
50
+ ```ruby
51
+ class Post < ActiveRecord::Base
52
+ searchable do
53
+ text :title, :body
54
+ text :comments do
55
+ comments.map { |comment| comment.body }
56
+ end
57
+
58
+ boolean :featured
59
+ integer :blog_id
60
+ integer :author_id
61
+ integer :category_ids, :multiple => true
62
+ double :average_rating
63
+ time :published_at
64
+ time :expired_at
65
+
66
+ string :sort_title do
67
+ title.downcase.gsub(/^(an?|the)/, '')
68
+ end
69
+ end
70
+ end
71
+ ```
72
+
73
+ `text` fields will be full-text searchable. Other fields (e.g.,
74
+ `integer` and `string`) can be used to scope queries.
75
+
76
+ ## Searching Objects
77
+
78
+ ```ruby
79
+ Post.search do
80
+ fulltext 'best pizza'
81
+
82
+ with :blog_id, 1
83
+ with(:published_at).less_than Time.now
84
+ order_by :published_at, :desc
85
+ paginate :page => 2, :per_page => 15
86
+ facet :category_ids, :author_id
87
+ end
88
+ ```
89
+
90
+ ## Search In Depth
91
+
92
+ Given an object `Post` setup in earlier steps ...
93
+
94
+ ### Full Text
95
+
96
+ ```ruby
97
+ # All posts with a `text` field (:title, :body, or :comments) containing 'pizza'
98
+ Post.search { fulltext 'pizza' }
99
+
100
+ # Posts with pizza, scored higher if pizza appears in the title
101
+ Post.search do
102
+ fulltext 'pizza' do
103
+ boost_fields :title => 2.0
104
+ end
105
+ end
106
+
107
+ # Posts with pizza, scored higher if featured
108
+ Post.search do
109
+ fulltext 'pizza' do
110
+ boost(2.0) { with(:featured, true) }
111
+ end
112
+ end
113
+
114
+ # Posts with pizza *only* in the title
115
+ Post.search do
116
+ fulltext 'pizza' do
117
+ fields(:title)
118
+ end
119
+ end
120
+
121
+ # Posts with pizza in the title (boosted) or in the body (not boosted)
122
+ Post.search do
123
+ fulltext 'pizza' do
124
+ fields(:body, :title => 2.0)
125
+ end
126
+ end
127
+ ```
128
+
129
+ #### Phrases
130
+
131
+ Solr allows searching for phrases: search terms that are close together.
132
+
133
+ In the default query parser used by Sunspot (dismax), phrase searches
134
+ are represented as a double quoted group of words.
135
+
136
+ ```ruby
137
+ # Posts with the exact phrase "great pizza"
138
+ Post.search do
139
+ fulltext '"great pizza"'
140
+ end
141
+ ```
142
+
143
+ If specified, **query_phrase_slop** sets the number of words that may
144
+ appear between the words in a phrase.
145
+
146
+ ```ruby
147
+ # One word can appear between the words in the phrase, so "great big pizza"
148
+ # also matches, in addition to "great pizza"
149
+ Post.search do
150
+ fulltext '"great pizza"' do
151
+ query_phrase_slop 1
152
+ end
153
+ end
154
+ ```
155
+
156
+ ##### Phrase Boosts
157
+
158
+ Phrase boosts add boost to terms that appear in close proximity;
159
+ the terms do not *have* to appear in a phrase, but if they do, the
160
+ document will score more highly.
161
+
162
+ ```ruby
163
+ # Matches documents with great and pizza, and scores documents more
164
+ # highly if the terms appear in a phrase in the title field
165
+ Post.search do
166
+ fulltext 'great pizza' do
167
+ phrase_fields :title => 2.0
168
+ end
169
+ end
170
+
171
+ # Matches documents with great and pizza, and scores documents more
172
+ # highly if the terms appear in a phrase (or with one word between them)
173
+ # in the title field
174
+ Post.search do
175
+ fulltext 'great pizza' do
176
+ phrase_fields :title => 2.0
177
+ phrase_slop 1
178
+ end
179
+ end
180
+ ```
181
+
182
+ ### Scoping (Scalar Fields)
183
+
184
+ Fields not defined as `text` (e.g., `integer`, `boolean`, `time`,
185
+ etc...) can be used to scope (restrict) queries before full-text
186
+ matching is performed.
187
+
188
+ #### Positive Restrictions
189
+
190
+ ```ruby
191
+ # Posts with a blog_id of 1
192
+ Post.search do
193
+ with(:blog_id, 1)
194
+ end
195
+
196
+ # Posts with an average rating between 3.0 and 5.0
197
+ Post.search do
198
+ with(:average_rating, 3.0..5.0)
199
+ end
200
+
201
+ # Posts with a category of 1, 3, or 5
202
+ Post.search do
203
+ with(:category_ids, [1, 3, 5])
204
+ end
205
+
206
+ # Posts published since a week ago
207
+ Post.search do
208
+ with(:published_at).greater_than(1.week.ago)
209
+ end
210
+ ```
211
+
212
+ #### Negative Restrictions
213
+
214
+ ```ruby
215
+ # Posts not in category 1 or 3
216
+ Post.search do
217
+ without(:category_ids, [1, 3])
218
+ end
219
+
220
+ # All examples in "positive" also work negated using `without`
221
+ ```
222
+
223
+ #### Disjunctions and Conjunctions
224
+
225
+ ```ruby
226
+ # Posts that do not have an expired time or have not yet expired
227
+ Post.search do
228
+ any_of do
229
+ with(:expired_at).greater_than(Time.now)
230
+ with(:expired_at, nil)
231
+ end
232
+ end
233
+ ```
234
+
235
+ ```ruby
236
+ # Posts with blog_id 1 and author_id 2
237
+ Post.search do
238
+ all_of do
239
+ with(:blog_id, 1)
240
+ with(:author_id, 2)
241
+ end
242
+ end
243
+ ```
244
+
245
+ Disjunctions and conjunctions may be nested
246
+
247
+ ```ruby
248
+ Post.search do
249
+ any_of do
250
+ with(:blog_id, 1)
251
+ all_of do
252
+ with(:blog_id, 2)
253
+ with(:category_ids, 3)
254
+ end
255
+ end
256
+ end
257
+ ```
258
+
259
+ #### Combined with Full-Text
260
+
261
+ Scopes/restrictions can be combined with full-text searching. The
262
+ scope/restriction pares down the objects that are searched for the
263
+ full-text term.
264
+
265
+ ```ruby
266
+ # Posts with blog_id 1 and 'pizza' in the title
267
+ Post.search do
268
+ with(:blog_id, 1)
269
+ fulltext("pizza")
270
+ end
271
+ ```
272
+
273
+ ### Pagination
274
+
275
+ **All results from Solr are paginated**
276
+
277
+ The results array that is returned has methods mixed in that allow it to
278
+ operate seamlessly with common pagination libraries like will\_paginate
279
+ and kaminari.
280
+
281
+ By default, Sunspot requests the first 30 results from Solr.
282
+
283
+ ```ruby
284
+ search = Post.search do
285
+ fulltext "pizza"
286
+ end
287
+
288
+ # Imagine there are 60 *total* results (at 30 results/page, that is two pages)
289
+ results = search.results # => Array with 30 Post elements
290
+
291
+ search.total # => 60
292
+
293
+ results.total_pages # => 2
294
+ results.first_page? # => true
295
+ results.last_page? # => false
296
+ results.previous_page # => nil
297
+ results.next_page # => 2
298
+ results.out_of_bounds? # => false
299
+ results.offset # => 0
300
+ ```
301
+
302
+ To retrieve the next page of results, recreate the search and use the
303
+ `paginate` method.
304
+
305
+ ```ruby
306
+ search = Post.search do
307
+ fulltext "pizza"
308
+ paginate :page => 2
309
+ end
310
+
311
+ # Again, imagine there are 60 total results; this is the second page
312
+ results = search.results # => Array with 30 Post elements
313
+
314
+ search.total # => 60
315
+
316
+ results.total_pages # => 2
317
+ results.first_page? # => false
318
+ results.last_page? # => true
319
+ results.previous_page # => 1
320
+ results.next_page # => nil
321
+ results.out_of_bounds? # => false
322
+ results.offset # => 30
323
+ ```
324
+
325
+ A custom number of results per page can be specified with the
326
+ `:per_page` option to `paginate`:
327
+
328
+ ```ruby
329
+ search = Post.search do
330
+ fulltext "pizza"
331
+ paginate :page => 1, :per_page => 50
332
+ end
333
+ ```
334
+
335
+ ### Faceting
336
+
337
+ Faceting is a feature of Solr that determines the number of documents
338
+ that match a given search *and* an additional criterion. This allows you
339
+ to build powerful drill-down interfaces for search.
340
+
341
+ Each facet returns zero or more rows, each of which represents a
342
+ particular criterion conjoined with the actual query being performed.
343
+ For **field facets**, each row represents a particular value for a given
344
+ field. For **query facets**, each row represents an arbitrary scope; the
345
+ facet itself is just a means of logically grouping the scopes.
346
+
347
+ #### Field Facets
348
+
349
+ ```ruby
350
+ # Posts that match 'pizza' returning counts for each :author_id
351
+ search = Post.search do
352
+ fulltext "pizza"
353
+ facet :author_id
354
+ end
355
+
356
+ search.facet(:author_id).rows.each do |facet|
357
+ puts "Author #{facet.value} has #{facet.count} pizza posts!"
358
+ end
359
+ ```
360
+
361
+ #### Query Facets
362
+
363
+ ```ruby
364
+ # Posts faceted by ranges of average ratings
365
+ search = Post.search do
366
+ facet(:average_rating) do
367
+ row(1.0..2.0) do
368
+ with(:average_rating, 1.0..2.0)
369
+ end
370
+ row(2.0..3.0) do
371
+ with(:average_rating, 2.0..3.0)
372
+ end
373
+ row(3.0..4.0) do
374
+ with(:average_rating, 3.0..4.0)
375
+ end
376
+ row(4.0..5.0) do
377
+ with(:average_rating, 4.0..5.0)
378
+ end
379
+ end
380
+ end
381
+
382
+ # e.g.,
383
+ # Number of posts with rating withing 1.0..2.0: 2
384
+ # Number of posts with rating withing 2.0..3.0: 1
385
+ search.facet(:average_rating).rows.each do |facet|
386
+ puts "Number of posts with rating withing #{facet.value}: #{facet.count}"
387
+ end
388
+ ```
389
+
390
+ ### Ordering
391
+
392
+ By default, Sunspot orders results by "score": the Solr-determined
393
+ relevancy metric. Sorting can be customized with the `order_by` method:
394
+
395
+ ```ruby
396
+ # Order by average rating, descending
397
+ Post.search do
398
+ fulltext("pizza")
399
+ order_by(:average_rating, :desc)
400
+ end
401
+
402
+ # Order by relevancy score and in the case of a tie, average rating
403
+ Post.search do
404
+ fulltext("pizza")
405
+
406
+ order_by(:score, :desc)
407
+ order_by(:average_rating, :desc)
408
+ end
409
+
410
+ # Randomized ordering
411
+ Post.search do
412
+ fulltext("pizza")
413
+ order_by(:random)
414
+ end
415
+ ```
416
+
417
+ ### Grouping
418
+
419
+ **Solr 3.3 and above**
420
+
421
+ Solr supports grouping documents, similar to an SQL `GROUP BY`. More
422
+ information about result grouping/field collapsing is available on the
423
+ [Solr Wiki](http://wiki.apache.org/solr/FieldCollapsing).
424
+
425
+ **Grouping is only supported on `string` fields that are not
426
+ multivalued. To group on a field of a different type (e.g., integer),
427
+ add a denormalized `string` type**
428
+
429
+ ```ruby
430
+ class Post < ActiveRecord::Base
431
+ searchable do
432
+ # Denormalized `string` field because grouping can only be performed
433
+ # on string fields
434
+ string(:blog_id_str) { |p| p.blog_id.to_s }
435
+ end
436
+ end
437
+
438
+ # Returns only the top scoring document per blog_id
439
+ search = Post.search do
440
+ group :blog_id_str
441
+ end
442
+
443
+ search.group(:blog_id_str).matches # Total number of matches to the query
444
+
445
+ search.group(:blog_id_str).groups.each do |group|
446
+ puts group.value # blog_id of the each document in the group
447
+
448
+ # By default, there is only one document per group (the highest
449
+ # scoring one); if `limit` is specified (see below), multiple
450
+ # documents can be returned per group
451
+ group.results.each do |result|
452
+ # ...
453
+ end
454
+ end
455
+ ```
456
+
457
+ Additional options are supported by the DSL:
458
+
459
+ ```ruby
460
+ # Returns the top 3 scoring documents per blog_id
461
+ Post.search do
462
+ group :blog_id_str do
463
+ limit 3
464
+ end
465
+ end
466
+
467
+ # Returns document ordered within each group by published_at (by
468
+ # default, the ordering is score)
469
+ Post.search do
470
+ group :blog_id_str do
471
+ order_by(:average_rating, :desc)
472
+ end
473
+ end
474
+
475
+ # Facet count is based on the most relevant document of each group
476
+ # matching the query (>= Solr 3.4)
477
+ Post.search do
478
+ group :blog_id_str do
479
+ truncate
480
+ end
481
+
482
+ facet :blog_id_str, :extra => :any
483
+ end
484
+ ```
485
+
486
+ ### Geospatial
487
+
488
+ **Experimental and unreleased. The DSL may change.**
489
+
490
+ Sunspot 2.0 supports geospatial features of Solr 3.1 and above.
491
+
492
+ Geospatial features require a field defined with `latlon`:
493
+
494
+ ```ruby
495
+ class Post < ActiveRecord::Base
496
+ searchable do
497
+ # ...
498
+ latlon(:location) { Sunspot::Util::Coordinates.new(lat, lon) }
499
+ end
500
+ end
501
+ ```
502
+
503
+ #### Filter By Radius
504
+
505
+ ```ruby
506
+ # Searches posts within 100 kilometers of (32, -68)
507
+ Post.search do
508
+ with(:location).in_radius(32, -68, 100)
509
+ end
510
+ ```
511
+
512
+ #### Filter By Radius (inexact with bbox)
513
+
514
+ ```ruby
515
+ # Searches posts within 100 kilometers of (32, -68) with `bbox`. This is
516
+ # an approximation so searches run quicker, but it may include other
517
+ # points that are slightly outside of the required distance
518
+ Post.search do
519
+ with(:location).in_radius(32, -68, 100, :bbox => true)
520
+ end
521
+ ```
522
+
523
+ #### Filter By Bounding Box
524
+
525
+ ```ruby
526
+ # Searches posts within the bounding box defined by the corners (45,
527
+ # -94) to (46, -93)
528
+ Post.search do
529
+ with(:location).in_bounding_box([45, -94], [46, -93])
530
+ end
531
+ ```
532
+
533
+ #### Sort By Distance
534
+
535
+ ```ruby
536
+ # Orders documents by closeness to (32, -68)
537
+ Post.search do
538
+ order_by_geodist(:location, 32, -68)
539
+ end
540
+ ```
541
+
542
+ ### Highlighting
543
+
544
+ Highlighting allows you to display snippets of the part of the document
545
+ that matched the query.
546
+
547
+ The fields you wish to highlight must be **stored**.
548
+
549
+ ```ruby
550
+ class Post < ActiveRecord::Base
551
+ searchable do
552
+ # ...
553
+ text :body, :stored => true
554
+ end
555
+ end
556
+ ```
557
+
558
+ Highlighting matches on the `body` field, for instance, can be acheived
559
+ like:
560
+
561
+ ```ruby
562
+ search = Post.search do
563
+ fulltext "pizza" do
564
+ highlight :body
565
+ end
566
+ end
567
+
568
+ # Will output something similar to:
569
+ # Post #1
570
+ # I really love *pizza*
571
+ # *Pizza* is my favorite thing
572
+ # Post #2
573
+ # Pepperoni *pizza* is delicious
574
+ search.hits.each do |hit|
575
+ puts "Post ##{hit.primary_key}"
576
+
577
+ hit.highlights(:body).each do |highlight|
578
+ puts " " + highlight.format { |word| "*#{word}*" }
579
+ end
580
+ end
581
+ ```
582
+
583
+ ### Functions
584
+
585
+ TODO
586
+
587
+ ### More Like This
588
+
589
+ Sunspot can extract related items using more_like_this. When searching
590
+ for similar items, you can pass a block with the following options:
591
+
592
+ * fields :field_1[, :field_2, ...]
593
+ * minimum_term_frequency ##
594
+ * minimum_document_frequency ##
595
+ * minimum_word_length ##
596
+ * maximum_word_length ##
597
+ * maximum_query_terms ##
598
+ * boost_by_relevance true/false
599
+
600
+ ```ruby
601
+ class Post < ActiveRecord::Base
602
+ searchable do
603
+ # The :more_like_this option must be set to true
604
+ text :body, :more_like_this => true
605
+ end
606
+ end
607
+
608
+ post = Post.first
609
+
610
+ results = Sunspot.more_like_this(post) do
611
+ fields :body
612
+ minimum_term_frequency 5
613
+ end
614
+ ```
615
+
616
+ ## Indexing In Depth
617
+
618
+ TODO
619
+
620
+ ### Index-Time Boosts
621
+
622
+ To specify that a field should be boosted in relation to other fields for
623
+ all queries, you can specify the boost at index time:
624
+
625
+ ```ruby
626
+ class Post < ActiveRecord::Base
627
+ searchable do
628
+ text :title, :boost => 5.0
629
+ text :body
630
+ end
631
+ end
632
+ ```
633
+
634
+ ### Stored Fields
635
+
636
+ Stored fields keep an original (untokenized/unanalyzed) version of their
637
+ contents in Solr.
638
+
639
+ Stored fields allow data to be retrieved without also hitting the
640
+ underlying database (usually an SQL server). They are also required for
641
+ highlighting and more like this queries.
642
+
643
+ Stored fields come at some performance cost in the Solr index, so use
644
+ them wisely.
645
+
646
+ ```ruby
647
+ class Post < ActiveRecord::Base
648
+ searchable do
649
+ text :body, :stored => true
650
+ end
651
+ end
652
+
653
+ # Retrieving stored contents without hitting the database
654
+ Post.search.hits.each do |hit|
655
+ puts hit.stored(:body)
656
+ end
657
+ ```
658
+
659
+ ## Hits vs. Results
660
+
661
+ Sunspot simply stores the type and primary key of objects in Solr.
662
+ When results are retrieved, those primary keys are used to load the
663
+ actual object (usually from an SQL database).
664
+
665
+ ```ruby
666
+ # Using #results pulls in the records from the object-relational
667
+ # mapper (e.g., ActiveRecord + a SQL server)
668
+ Post.search.results.each do |result|
669
+ puts result.body
670
+ end
671
+ ```
672
+
673
+ To access information about the results without querying the underlying
674
+ database, use `hits`:
675
+
676
+ ```ruby
677
+ # Using #hits gives back all information requested from Solr, but does
678
+ # not load the object from the object-relational mapper
679
+ Post.search.hits.each do |hit|
680
+ puts hit.stored(:body)
681
+ end
682
+ ```
683
+
684
+ If you need both the result (ORM-loaded object) and `Hit` (e.g., for
685
+ faceting, highlighting, etc...), you can use the convenience method
686
+ `each_hit_with_result`:
687
+
688
+ ```ruby
689
+ Post.search.each_hit_with_result do |hit, result|
690
+ # ...
691
+ end
692
+ ```
693
+
694
+ ## Reindexing Objects
695
+
696
+ If you are using Rails, objects are automatically indexed to Solr as a
697
+ part of the `save` callbacks.
698
+
699
+ If you make a change to the object's "schema" (code in the `searchable` block),
700
+ you must reindex all objects so the changes are reflected in Solr:
701
+
702
+ ```bash
703
+ bundle exec rake sunspot:solr:reindex
704
+
705
+ # or, to be specific to a certain model with a certain batch size:
706
+ bundle exec rake sunspot:solr:reindex[500,Post] # some shells will require escaping [ with \[ and ] with \]
707
+ ```
708
+
709
+ ## Use Without Rails
710
+
711
+ TODO
712
+
713
+ ## Manually Adjusting Solr Parameters
714
+
715
+ To add or modify parameters sent to Solr, use `adjust_solr_params`:
716
+
717
+ ```ruby
718
+ Post.search do
719
+ adjust_solr_params do |params|
720
+ params[:q] += " AND something_s:more"
721
+ end
722
+ end
723
+ ```
724
+
725
+ ## Session Proxies
726
+
727
+ TODO
728
+
729
+ ## Type Reference
730
+
731
+ TODO
732
+
733
+ ## Development
734
+
735
+ ### Running Tests
736
+
737
+ #### sunspot
738
+
739
+ Install the required gem dependencies:
740
+
741
+ ```bash
742
+ cd /path/to/sunspot/sunspot
743
+ bundle install
744
+ ```
745
+
746
+ Start a Solr instance on port 8983:
747
+
748
+ ```bash
749
+ bundle exec sunspot-solr start -p 8983
750
+ # or `bundle exec sunspot-solr run -p 8983` to run in foreground
751
+ ```
752
+
753
+ Run the tests:
754
+
755
+ ```bash
756
+ bundle exec rake spec
757
+ ```
758
+
759
+ If desired, stop the Solr instance:
760
+
761
+ ```bash
762
+ bundle exec sunspot-solr stop
763
+ ```
764
+
765
+ #### sunspot\_rails
766
+
767
+ Install the gem dependencies for `sunspot`:
768
+
769
+ ```bash
770
+ cd /path/to/sunspot/sunspot
771
+ bundle install
772
+ ```
773
+
774
+ Start a Solr instance on port 8983:
775
+
776
+ ```bash
777
+ bundle exec sunspot-solr start -p 8983
778
+ # or `bundle exec sunspot-solr run -p 8983` to run in foreground
779
+ ```
780
+
781
+ Navigate to the `sunspot_rails` directory:
782
+
783
+ ```bash
784
+ cd ../sunspot_rails
785
+ ```
786
+
787
+ Run the tests:
788
+
789
+ ```bash
790
+ rake spec # all Rails versions
791
+ rake spec RAILS=3.1.1 # specific Rails version only
792
+ ```
793
+
794
+ If desired, stop the Solr instance:
795
+
796
+ ```bash
797
+ cd ../sunspot
798
+ bundle exec sunspot-solr stop
799
+ ```
800
+
801
+ ### Generating Documentation
802
+
803
+ Install the `yard` and `redcarpet` gems:
804
+
805
+ ```bash
806
+ $ gem install yard redcarpet
807
+ ```
808
+
809
+ Uninstall the `rdiscount` gem, if installed:
810
+
811
+ ```bash
812
+ $ gem uninstall rdiscount
813
+ ```
814
+
815
+ Generate the documentation from topmost directory:
816
+
817
+ ```bash
818
+ $ yardoc -o docs */lib/**/*.rb - README.md
819
+ ```
820
+
821
+ ## Tutorials and Articles
822
+
823
+ * [Full Text Searching with Solr and Sunspot](http://collectiveidea.com/blog/archives/2011/03/08/full-text-searching-with-solr-and-sunspot/) (Collective Idea)
824
+ * [Full-text search in Rails with Sunspot](http://tech.favoritemedium.com/2010/01/full-text-search-in-rails-with-sunspot.html) (Tropical Software Observations)
825
+ * [Sunspot Full-text Search for Rails/Ruby](http://therailworld.com/posts/23-Sunspot-Full-text-Search-for-Rails-Ruby) (The Rail World)
826
+ * [A Few Sunspot Tips](http://blog.trydionel.com/2009/11/19/a-few-sunspot-tips/) (spiral_code)
827
+ * [Sunspot: A Solr-Powered Search Engine for Ruby](http://www.linux-mag.com/id/7341) (Linux Magazine)
828
+ * [Sunspot Showed Me the Light](http://bennyfreshness.com/2010/05/sunspot-helped-me-see-the-light/) (ben koonse)
829
+ * [RubyGems.org — A case study in upgrading to full-text search](http://blog.websolr.com/post/3505903537/rubygems-search-upgrade-1) (Websolr)
830
+ * [How to Implement Spatial Search with Sunspot and Solr](http://codequest.eu/articles/how-to-implement-spatial-search-with-sunspot-and-solr) (Code Quest)
831
+ * [Sunspot 1.2 with Spatial Solr Plugin 2.0](http://joelmats.wordpress.com/2011/02/23/getting-sunspot-1-2-with-spatial-solr-plugin-2-0-to-work/) (joelmats)
832
+ * [rails3 + heroku + sunspot : madness](http://anhaminha.tumblr.com/post/632682537/rails3-heroku-sunspot-madness) (anhaminha)
833
+ * [How to get full text search working with Sunspot](http://cookbook.hobocentral.net/recipes/57-how-to-get-full-text-search) (Hobo Cookbook)
834
+ * [Full text search with Sunspot in Rails](http://hemju.com/2011/01/04/full-text-search-with-sunspot-in-rail/) (hemju)
835
+ * [Using Sunspot for Free-Text Search with Redis](http://masonoise.wordpress.com/2010/02/06/using-sunspot-for-free-text-search-with-redis/) (While I Pondered...)
836
+ * [Fuzzy searching in SOLR with Sunspot](http://www.pipetodevnull.com/past/2010/8/5/fuzzy_searching_in_solr_with_sunspot/) (pipe :to => /dev/null)
837
+ * [Default scope with Sunspot](http://www.cloudspace.com/blog/2010/01/15/default-scope-with-sunspot/) (Cloudspace)
838
+ * [Index External Models with Sunspot/Solr](http://www.medihack.org/2011/03/19/index-external-models-with-sunspotsolr/) (Medihack)
839
+ * [Chef recipe for Sunspot in production](http://gist.github.com/336403)
840
+ * [Testing with Sunspot and Cucumber](http://collectiveidea.com/blog/archives/2011/05/25/testing-with-sunspot-and-cucumber/) (Collective Idea)
841
+ * [Cucumber and Sunspot](http://opensoul.org/2010/4/7/cucumber-and-sunspot) (opensoul.org)
842
+ * [Testing Sunspot with Cucumber](http://blog.trydionel.com/2010/02/06/testing-sunspot-with-cucumber/) (spiral_code)
843
+ * [Running cucumber features with sunspot_rails](http://blog.kabisa.nl/2010/02/03/running-cucumber-features-with-sunspot_rails) (Kabisa Blog)
844
+ * [Testing Sunspot with Test::Unit](http://timcowlishaw.co.uk/post/3179661158/testing-sunspot-with-test-unit) (Type Slowly)
845
+ * [How To Use Twitter Lists to Determine Influence](http://www.untitledstartup.com/2010/01/how-to-use-twitter-lists-to-determine-influence/) (Untitled Startup)
846
+ * [Sunspot Quickstart](http://wiki.websolr.com/index.php/Sunspot_Quickstart) (WebSolr)
847
+ * [Solr, and Sunspot](http://www.kuahyeow.com/2009/08/solr-and-sunspot.html) (YT!)
848
+ * [The Saga of the Switch](http://mrb.github.com/2010/04/08/the-saga-of-the-switch.html) (mrb -- includes comparison of Sunspot and Ultrasphinx)
849
+ * [Conditional Indexing with Sunspot](http://mikepackdev.com/blog_posts/19-conditional-indexing-with-sunspot) (mikepack)
850
+
851
+ ## License
852
+
853
+ Sunspot is distributed under the MIT License, copyright (c) 2008-2009 Mat Brown
@@ -1,11 +1,11 @@
1
1
  module Sunspot
2
2
  module Query
3
- #
3
+ #
4
4
  # The classes in this module implement query components that build sort
5
5
  # parameters for Solr. As well as regular sort on fields, there are several
6
6
  # "special" sorts that allow ordering for metrics calculated during the
7
7
  # search.
8
- #
8
+ #
9
9
  module Sort #:nodoc: all
10
10
  DIRECTIONS = {
11
11
  :asc => 'asc',
@@ -15,7 +15,7 @@ module Sunspot
15
15
  }
16
16
 
17
17
  class <<self
18
- #
18
+ #
19
19
  # Certain field names are "special", referring to specific non-field
20
20
  # sorts, which are generally by other metrics associated with hits.
21
21
  #
@@ -30,7 +30,7 @@ module Sunspot
30
30
  end
31
31
  end
32
32
 
33
- #
33
+ #
34
34
  # Base class for sorts. All subclasses should implement the #to_param
35
35
  # method, which is a string that is then concatenated with other sort
36
36
  # strings by the SortComposite to form the sort parameter.
@@ -42,11 +42,11 @@ module Sunspot
42
42
 
43
43
  private
44
44
 
45
- #
45
+ #
46
46
  # Translate fairly forgiving direction argument into solr direction
47
47
  #
48
48
  def direction_for_solr
49
- DIRECTIONS[@direction] ||
49
+ DIRECTIONS[@direction] ||
50
50
  raise(
51
51
  ArgumentError,
52
52
  "Unknown sort direction #{@direction}. Acceptable input is: #{DIRECTIONS.keys.map { |input| input.inspect } * ', '}"
@@ -54,7 +54,7 @@ module Sunspot
54
54
  end
55
55
  end
56
56
 
57
- #
57
+ #
58
58
  # A FieldSort is the usual kind of sort, by the value of a particular
59
59
  # field, ascending or descending
60
60
  #
@@ -71,17 +71,21 @@ module Sunspot
71
71
  end
72
72
  end
73
73
 
74
- #
74
+ #
75
75
  # A RandomSort uses Solr's random field functionality to sort results
76
76
  # (usually) randomly.
77
77
  #
78
78
  class RandomSort < Abstract
79
+ def initialize(options={:seed => rand(1<<16)}, direction=nil)
80
+ @seed, @direction = options[:seed], (direction || :asc).to_sym
81
+ end
82
+
79
83
  def to_param
80
- "random_#{rand(1<<16)} #{direction_for_solr}"
84
+ "random_#{@seed} #{direction_for_solr}"
81
85
  end
82
86
  end
83
87
 
84
- #
88
+ #
85
89
  # A ScoreSort sorts by keyword relevance score. This is only useful when
86
90
  # performing fulltext search.
87
91
  #
@@ -1,3 +1,3 @@
1
1
  module Sunspot
2
- VERSION = '2.0.4'
2
+ VERSION = '2.0.5'
3
3
  end
metadata CHANGED
@@ -1,10 +1,14 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: gojee-sunspot
3
- version: !ruby/object:Gem::Version
4
- version: 2.0.4
5
- prerelease:
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 2
7
+ - 0
8
+ - 5
9
+ version: 2.0.5
6
10
  platform: ruby
7
- authors:
11
+ authors:
8
12
  - Mat Brown
9
13
  - Peer Allan
10
14
  - Dmitriy Dzema
@@ -27,102 +31,91 @@ authors:
27
31
  autorequire:
28
32
  bindir: bin
29
33
  cert_chain: []
30
- date: 2012-09-03 00:00:00.000000000 Z
31
- dependencies:
32
- - !ruby/object:Gem::Dependency
34
+
35
+ date: 2012-11-05 00:00:00 -05:00
36
+ default_executable:
37
+ dependencies:
38
+ - !ruby/object:Gem::Dependency
33
39
  name: rsolr
34
- requirement: !ruby/object:Gem::Requirement
35
- none: false
36
- requirements:
37
- - - ~>
38
- - !ruby/object:Gem::Version
39
- version: 1.0.6
40
- type: :runtime
41
40
  prerelease: false
42
- version_requirements: !ruby/object:Gem::Requirement
43
- none: false
44
- requirements:
41
+ requirement: &id001 !ruby/object:Gem::Requirement
42
+ requirements:
45
43
  - - ~>
46
- - !ruby/object:Gem::Version
44
+ - !ruby/object:Gem::Version
45
+ segments:
46
+ - 1
47
+ - 0
48
+ - 6
47
49
  version: 1.0.6
48
- - !ruby/object:Gem::Dependency
49
- name: escape
50
- requirement: !ruby/object:Gem::Requirement
51
- none: false
52
- requirements:
53
- - - ~>
54
- - !ruby/object:Gem::Version
55
- version: 0.0.4
56
50
  type: :runtime
51
+ version_requirements: *id001
52
+ - !ruby/object:Gem::Dependency
53
+ name: escape
57
54
  prerelease: false
58
- version_requirements: !ruby/object:Gem::Requirement
59
- none: false
60
- requirements:
55
+ requirement: &id002 !ruby/object:Gem::Requirement
56
+ requirements:
61
57
  - - ~>
62
- - !ruby/object:Gem::Version
58
+ - !ruby/object:Gem::Version
59
+ segments:
60
+ - 0
61
+ - 0
62
+ - 4
63
63
  version: 0.0.4
64
- - !ruby/object:Gem::Dependency
65
- name: pr_geohash
66
- requirement: !ruby/object:Gem::Requirement
67
- none: false
68
- requirements:
69
- - - ~>
70
- - !ruby/object:Gem::Version
71
- version: '1.0'
72
64
  type: :runtime
65
+ version_requirements: *id002
66
+ - !ruby/object:Gem::Dependency
67
+ name: pr_geohash
73
68
  prerelease: false
74
- version_requirements: !ruby/object:Gem::Requirement
75
- none: false
76
- requirements:
69
+ requirement: &id003 !ruby/object:Gem::Requirement
70
+ requirements:
77
71
  - - ~>
78
- - !ruby/object:Gem::Version
79
- version: '1.0'
80
- - !ruby/object:Gem::Dependency
72
+ - !ruby/object:Gem::Version
73
+ segments:
74
+ - 1
75
+ - 0
76
+ version: "1.0"
77
+ type: :runtime
78
+ version_requirements: *id003
79
+ - !ruby/object:Gem::Dependency
81
80
  name: rspec
82
- requirement: !ruby/object:Gem::Requirement
83
- none: false
84
- requirements:
85
- - - ~>
86
- - !ruby/object:Gem::Version
87
- version: 2.6.0
88
- type: :development
89
81
  prerelease: false
90
- version_requirements: !ruby/object:Gem::Requirement
91
- none: false
92
- requirements:
82
+ requirement: &id004 !ruby/object:Gem::Requirement
83
+ requirements:
93
84
  - - ~>
94
- - !ruby/object:Gem::Version
85
+ - !ruby/object:Gem::Version
86
+ segments:
87
+ - 2
88
+ - 6
89
+ - 0
95
90
  version: 2.6.0
96
- - !ruby/object:Gem::Dependency
97
- name: hanna
98
- requirement: !ruby/object:Gem::Requirement
99
- none: false
100
- requirements:
101
- - - ! '>='
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
91
  type: :development
92
+ version_requirements: *id004
93
+ - !ruby/object:Gem::Dependency
94
+ name: hanna
105
95
  prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- none: false
108
- requirements:
109
- - - ! '>='
110
- - !ruby/object:Gem::Version
111
- version: '0'
112
- description: ! " Sunspot is a library providing a powerful, all-ruby API for the
113
- Solr search engine. Sunspot manages the configuration of persistent\n Ruby classes
114
- for search and indexing and exposes Solr's most powerful features through a collection
115
- of DSLs. Complex search operations\n can be performed without hand-writing any
116
- boolean queries or building Solr parameters by hand.\n"
96
+ requirement: &id005 !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ segments:
101
+ - 0
102
+ version: "0"
103
+ type: :development
104
+ version_requirements: *id005
105
+ description: " Sunspot is a library providing a powerful, all-ruby API for the Solr search engine. Sunspot manages the configuration of persistent\n Ruby classes for search and indexing and exposes Solr's most powerful features through a collection of DSLs. Complex search operations\n can be performed without hand-writing any boolean queries or building Solr parameters by hand.\n"
117
106
  email: mat@patch.com
118
107
  executables: []
108
+
119
109
  extensions: []
110
+
120
111
  extra_rdoc_files: []
121
- files:
112
+
113
+ files:
122
114
  - .gitignore
123
115
  - Gemfile
124
116
  - History.txt
125
117
  - LICENSE
118
+ - README.md
126
119
  - Rakefile
127
120
  - TODO
128
121
  - lib/light_config.rb
@@ -296,36 +289,41 @@ files:
296
289
  - tasks/rdoc.rake
297
290
  - tasks/schema.rake
298
291
  - tasks/todo.rake
292
+ has_rdoc: true
299
293
  homepage: http://outoftime.github.com/sunspot
300
294
  licenses: []
295
+
301
296
  post_install_message:
302
- rdoc_options:
297
+ rdoc_options:
303
298
  - --webcvs=http://github.com/outoftime/sunspot/tree/master/%s
304
299
  - --title
305
300
  - Sunspot - Solr-powered search for Ruby objects - API Documentation
306
301
  - --main
307
302
  - README.rdoc
308
- require_paths:
303
+ require_paths:
309
304
  - lib
310
- required_ruby_version: !ruby/object:Gem::Requirement
311
- none: false
312
- requirements:
313
- - - ! '>='
314
- - !ruby/object:Gem::Version
315
- version: '0'
316
- required_rubygems_version: !ruby/object:Gem::Requirement
317
- none: false
318
- requirements:
319
- - - ! '>='
320
- - !ruby/object:Gem::Version
321
- version: '0'
305
+ required_ruby_version: !ruby/object:Gem::Requirement
306
+ requirements:
307
+ - - ">="
308
+ - !ruby/object:Gem::Version
309
+ segments:
310
+ - 0
311
+ version: "0"
312
+ required_rubygems_version: !ruby/object:Gem::Requirement
313
+ requirements:
314
+ - - ">="
315
+ - !ruby/object:Gem::Version
316
+ segments:
317
+ - 0
318
+ version: "0"
322
319
  requirements: []
320
+
323
321
  rubyforge_project: sunspot
324
- rubygems_version: 1.8.24
322
+ rubygems_version: 1.3.6
325
323
  signing_key:
326
324
  specification_version: 3
327
325
  summary: Library for expressive, powerful interaction with the Solr search engine
328
- test_files:
326
+ test_files:
329
327
  - spec/api/adapters_spec.rb
330
328
  - spec/api/batcher_spec.rb
331
329
  - spec/api/binding_spec.rb