pallan-sunspot 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/History.txt +39 -0
  2. data/LICENSE +18 -0
  3. data/README.rdoc +158 -0
  4. data/Rakefile +11 -0
  5. data/TODO +6 -0
  6. data/VERSION.yml +4 -0
  7. data/bin/sunspot-solr +46 -0
  8. data/lib/light_config.rb +40 -0
  9. data/lib/sunspot.rb +404 -0
  10. data/lib/sunspot/adapters.rb +253 -0
  11. data/lib/sunspot/configuration.rb +32 -0
  12. data/lib/sunspot/data_extractor.rb +37 -0
  13. data/lib/sunspot/dsl.rb +3 -0
  14. data/lib/sunspot/dsl/fields.rb +59 -0
  15. data/lib/sunspot/dsl/query.rb +78 -0
  16. data/lib/sunspot/dsl/restriction.rb +25 -0
  17. data/lib/sunspot/dsl/scope.rb +137 -0
  18. data/lib/sunspot/facet.rb +37 -0
  19. data/lib/sunspot/facet_row.rb +34 -0
  20. data/lib/sunspot/field.rb +234 -0
  21. data/lib/sunspot/indexer.rb +81 -0
  22. data/lib/sunspot/query.rb +372 -0
  23. data/lib/sunspot/query/dynamic_query.rb +86 -0
  24. data/lib/sunspot/query/field_facet.rb +21 -0
  25. data/lib/sunspot/query/pagination.rb +39 -0
  26. data/lib/sunspot/query/restriction.rb +223 -0
  27. data/lib/sunspot/query/sort.rb +33 -0
  28. data/lib/sunspot/search.rb +159 -0
  29. data/lib/sunspot/session.rb +159 -0
  30. data/lib/sunspot/setup.rb +200 -0
  31. data/lib/sunspot/type.rb +154 -0
  32. data/lib/sunspot/util.rb +164 -0
  33. data/solr/etc/jetty.xml +212 -0
  34. data/solr/etc/webdefault.xml +379 -0
  35. data/solr/lib/jetty-6.1.3.jar +0 -0
  36. data/solr/lib/jetty-util-6.1.3.jar +0 -0
  37. data/solr/lib/jsp-2.1/ant-1.6.5.jar +0 -0
  38. data/solr/lib/jsp-2.1/core-3.1.1.jar +0 -0
  39. data/solr/lib/jsp-2.1/jsp-2.1.jar +0 -0
  40. data/solr/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
  41. data/solr/lib/servlet-api-2.5-6.1.3.jar +0 -0
  42. data/solr/solr/conf/elevate.xml +36 -0
  43. data/solr/solr/conf/protwords.txt +21 -0
  44. data/solr/solr/conf/schema.xml +231 -0
  45. data/solr/solr/conf/solrconfig.xml +696 -0
  46. data/solr/solr/conf/stopwords.txt +57 -0
  47. data/solr/solr/conf/synonyms.txt +31 -0
  48. data/solr/start.jar +0 -0
  49. data/solr/webapps/solr.war +0 -0
  50. data/spec/api/build_search_spec.rb +419 -0
  51. data/spec/api/indexer_spec.rb +214 -0
  52. data/spec/api/query_spec.rb +129 -0
  53. data/spec/api/search_retrieval_spec.rb +148 -0
  54. data/spec/api/session_spec.rb +102 -0
  55. data/spec/api/spec_helper.rb +1 -0
  56. data/spec/integration/dynamic_fields_spec.rb +55 -0
  57. data/spec/integration/faceting_spec.rb +39 -0
  58. data/spec/integration/keyword_search_spec.rb +32 -0
  59. data/spec/integration/scoped_search_spec.rb +175 -0
  60. data/spec/integration/spec_helper.rb +1 -0
  61. data/spec/integration/test_pagination.rb +32 -0
  62. data/spec/mocks/base_class.rb +2 -0
  63. data/spec/mocks/comment.rb +28 -0
  64. data/spec/mocks/mock_adapter.rb +22 -0
  65. data/spec/mocks/post.rb +75 -0
  66. data/spec/mocks/user.rb +8 -0
  67. data/spec/spec_helper.rb +32 -0
  68. data/tasks/gemspec.rake +22 -0
  69. data/tasks/rcov.rake +28 -0
  70. data/tasks/rdoc.rake +21 -0
  71. data/tasks/spec.rake +24 -0
  72. data/tasks/todo.rake +4 -0
  73. metadata +175 -0
@@ -0,0 +1,39 @@
1
+ == 0.8.0 2009-05-22
2
+ * Access query API directly; instantiate search without running it
3
+ * Dynamic fields
4
+ * Search blocks can be evaluated in calling context
5
+
6
+ == 0.7.3 2009-05-06
7
+ * Better exception handling when class doesn't have adapter/setup
8
+
9
+ == 0.7.2 2009-04-29
10
+ * Dirty sessions
11
+
12
+ == 0.7.1 2009-04-29
13
+ * Removed extlib dependency from gemspec
14
+
15
+ == 0.7.0 2009-04-28
16
+ * Less magic in the DSL
17
+ * Restrict by empty values
18
+ * Negative scoping using without() method
19
+ * Exclusion by object identity using without(instance)
20
+ * Support for faceting
21
+ * Explicit commits
22
+ * Boolean field type
23
+ * Attribute field flexibility
24
+ * Virtual field blocks can be evaluated in calling context
25
+ * Order available by multiple fields
26
+ * New adapter API
27
+ * Got rid of builder API
28
+ * Full documentation
29
+
30
+ == 0.0.2 2009-02-14
31
+ * Run sunspot's built-in Solr instance using
32
+ sunspot-solr executable
33
+ * Search hash interpretation delegated to
34
+ Builder object
35
+
36
+ == 0.0.1 2008-12-11
37
+ * Initial release
38
+ * Define indexing for any class using DSL
39
+ * Search indexed classes using DSL
data/LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ Permission is hereby granted, free of charge, to any person obtaining
2
+ a copy of this software and associated documentation files (the
3
+ 'Software'), to deal in the Software without restriction, including
4
+ without limitation the rights to use, copy, modify, merge, publish,
5
+ distribute, sublicense, and/or sell copies of the Software, and to
6
+ permit persons to whom the Software is furnished to do so, subject to
7
+ the following conditions:
8
+
9
+ The above copyright notice and this permission notice shall be
10
+ included in all copies or substantial portions of the Software.
11
+
12
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
13
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
15
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
16
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
17
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
18
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,158 @@
1
+ = Sunspot
2
+
3
+ http://outoftime.github.com/sunspot
4
+
5
+ Sunspot is a Ruby library for expressive, powerful interaction with the Solr search engine.
6
+ Sunspot is built on top of the solr-ruby gem, which provides a low-level interface for Solr
7
+ interaction; Sunspot provides a simple, intuitive, expressive DSL backed by powerful
8
+ features for indexing objects and searching for them.
9
+
10
+ Sunspot is designed to be easily plugged in to any ORM, or even non-database-backed
11
+ objects such as the filesystem.
12
+
13
+ === Features:
14
+
15
+ * Define indexing strategy for each searchable class using intuitive block-based API
16
+ * Clean separation between keyword-searchable fields and fields for scoping/ordering
17
+ * Define fields based on existing attributes or "virtual fields" for custom indexing
18
+ * Indexes each object's entire superclass hierarchy, for easy searching for all objects inheriting from a parent class
19
+ * Intuitive DSL for scoping searches, with all the usual boolean operators available
20
+ * Intuitive interface for requesting facets on indexed fields
21
+ * Extensible adapter architecture for easy integration of other ORMs or non-model classes
22
+ * Full compatibility with will_paginate
23
+ * Ordering
24
+
25
+ == Installation
26
+
27
+ gem sources -a http://gems.github.com
28
+ gem install outoftime-sunspot
29
+
30
+ In order to start the packaged Solr installation, run:
31
+
32
+ sunspot-solr start -- [-d /path/to/data/directory] [-p port] [-s path/to/solr/home]
33
+
34
+ If you don't specify a data directory, your Solr index will be stored in your operating system's temporary directory.
35
+
36
+ If you specify a solr home, the directory must contain a <code>conf</code>
37
+ directory, which should contain at least <code>schema.xml</code> and
38
+ <code>solrconfig.xml</code>. Be sure to copy the <code>schema.xml</code> out of
39
+ the Sunspot gem's <code>solr/solr/conf</code> directory. Sunspot relies on the
40
+ field name patterns defined in the packaged <code>schema.xml</code>, so those
41
+ cannot be modified.
42
+
43
+ You can also run your own instance of Solr wherever you'd like; just copy the solr/config/schema.xml file out of the gem's solr into your installation.
44
+ You can change the URL at which Sunspot accesses Solr with:
45
+
46
+ Sunspot.config.solr.url = 'http://solr.my.host:9818/solr'
47
+
48
+ == Rails Integration
49
+
50
+ The {Sunspot::Rails}[http://github.com/outoftime/sunspot_rails] plugin makes
51
+ integrating Sunspot into Rails drop-in easy.
52
+
53
+ == Using Sunspot
54
+
55
+ === Define an index:
56
+
57
+ class Post
58
+ #...
59
+ end
60
+
61
+ Sunspot.setup(Post) do
62
+ text :title, :body
63
+ string :author_name
64
+ integer :blog_id
65
+ integer :category_ids
66
+ float :average_rating, :using => :ratings_average
67
+ time :published_at
68
+ string :sort_title do
69
+ title.downcase.sub(/^(an?|the)\W+/, ''/) if title = self.title
70
+ end
71
+ end
72
+
73
+ See Sunspot.setup for more information.
74
+
75
+ Note that in order for a class to be searchable, it must have an adapter
76
+ registered for itself or one of its subclasses. Adapters allow Sunspot to load
77
+ objects out of persistent storage, and to determine their primary key for
78
+ indexing. {Sunspot::Rails}[http://github.com/outoftime/sunspot_rails] comes with
79
+ an adapter for ActiveRecord objects, but for other types of models you will need
80
+ to define your own. See Sunspot::Adapters for more information.
81
+
82
+ === Search for objects:
83
+
84
+ search = Sunspot.search Post do
85
+ keywords 'great pizza'
86
+ with :author_name, 'Mark Twain'
87
+ with(:blog_id).any_of [2, 14]
88
+ with(:category_ids).all_of [4, 10]
89
+ with(:published_at).less_than Time.now
90
+ without :title, 'Bad Title'
91
+ without bad_instance # specifically exclude this instance from results
92
+
93
+ paginate :page => 3, :per_page => 15
94
+ order_by :average_rating, :desc
95
+
96
+ facet :blog_id
97
+ end
98
+
99
+ See Sunspot.search for more information.
100
+
101
+ === Get data from search:
102
+
103
+ search.results
104
+ search.total
105
+ search.page
106
+ search.per_page
107
+ search.facet(:blog_id)
108
+
109
+ === Building searches manually:
110
+
111
+ The search DSL is great for building searches from fairly static parameters,
112
+ but a highly dynamic search might want to leverage an intermediate approach
113
+ (such as an application of the Builder pattern). For these cases, Sunspot
114
+ exposes direct access to the Query object:
115
+
116
+ search = Sunspot.new_search(Post)
117
+ search.query.keywords = 'great pizza'
118
+ search.query.add_restriction(:author_name, :equal_to, 'Mark Twain')
119
+ search.query.add_restriction(:title, :equal_to, 'Bad Title', true) # negate the restriction
120
+ search.query.exclude_instance(bad_instance)
121
+ search.query.paginate(3, 15)
122
+ search.query.order_by(:average_rating, :desc)
123
+ search.query.add_field_facet(:blog_id)
124
+ search.execute!
125
+
126
+ == About the API documentation
127
+
128
+ All of the methods documented in the RDoc are considered part of Sunspot's
129
+ public API. Methods that are not part of the public API are documented in the
130
+ code, but excluded from the RDoc. If you find yourself needing to access methods
131
+ that are not part of the public API in order to do what you need, please contact
132
+ me so I can rectify the situation!
133
+
134
+ == Dependencies
135
+
136
+ 1. solr-ruby
137
+ 2. Java
138
+
139
+ Sunspot has been tested with MRI 1.8.6, YARV 1.9.1, and JRuby 1.2.0
140
+
141
+ == Bugs
142
+
143
+ Please submit bug reports to
144
+ http://outoftime.lighthouseapp.com/projects/20339-sunspot
145
+
146
+ == Further Reading
147
+
148
+ * Sunspot Discussion: http://groups.google.com/group/ruby-sunspot
149
+ * Posts about Sunspot from my tumblog: http://outofti.me/tagged/sunspot
150
+ * Read about it on Linux Magazine: http://www.linux-mag.com/id/7341
151
+
152
+ == Contributors
153
+
154
+ Mat Brown (mat@patch.com)
155
+
156
+ == License
157
+
158
+ Sunspot is distributed under the MIT License, copyright (c) 2008-2009 Mat Brown
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+
3
+ ENV['RUBYOPT'] = '-W1'
4
+
5
+ task :environment do
6
+ require File.dirname(__FILE__) + '/lib/sunspot'
7
+ end
8
+
9
+ Dir['tasks/**/*.rake'].each { |t| load t }
10
+
11
+ task :default => 'spec:api'
data/TODO ADDED
@@ -0,0 +1,6 @@
1
+ === 0.9 ===
2
+ * Instantiated facets!
3
+ * Direct access to adapter
4
+ * Facet by type (?)
5
+ * Switch to RSolr
6
+ * Query-based faceting (?)
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 8
4
+ :patch: 3
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ gem 'daemons', '~> 1.0'
4
+ gem 'optiflag', '~> 0.6.5'
5
+ require 'fileutils'
6
+ require 'tmpdir'
7
+ require 'daemons'
8
+ require 'optiflag'
9
+
10
+ working_directory = FileUtils.pwd
11
+ solr_home = File.join(File.dirname(__FILE__), '..', 'solr')
12
+
13
+ module SolrFlags extend OptiFlagSet
14
+ optional_flag 'p' do
15
+ description 'Port on which to run Solr (default 8983)'
16
+ long_form 'port'
17
+ end
18
+
19
+ optional_flag 'd' do
20
+ description 'Solr data directory'
21
+ end
22
+
23
+ optional_flag 's' do
24
+ description 'Solr home (should contain conf/ directory)'
25
+ end
26
+
27
+ and_process!
28
+ end
29
+
30
+ port = ARGV.flags.p || '8983'
31
+ data_dir = File.expand_path(ARGV.flags.d || File.join(Dir.tmpdir, 'solr_data'))
32
+ home = File.expand_path(ARGV.flags.s) if ARGV.flags.s
33
+
34
+ Daemons.run_proc('sunspot-solr') do
35
+ FileUtils.cd(working_directory) do
36
+ FileUtils.cd(solr_home) do
37
+ args = ['java']
38
+ args << "-Djetty.port=#{port}" if port
39
+ args << "-Dsolr.data.dir=#{data_dir}" if data_dir
40
+ args << "-Dsolr.solr.home=#{home}" if home
41
+ args << '-jar' << 'start.jar'
42
+ STDERR.puts(args * ' ')
43
+ Kernel.exec(*args)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,40 @@
1
+ module LightConfig
2
+ class Configuration
3
+ def initialize(&block)
4
+ @properties = {}
5
+ ::LightConfig::Builder.new(self).instance_eval(&block)
6
+ singleton = (class <<self; self; end)
7
+ @properties.keys.each do |property|
8
+ singleton.module_eval do
9
+ define_method property do
10
+ @properties[property]
11
+ end
12
+
13
+ define_method "#{property}=" do |value|
14
+ @properties[property] = value
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ class Builder
22
+ def initialize(configuration)
23
+ @configuration = configuration
24
+ end
25
+
26
+ def method_missing(method, *args, &block)
27
+ raise ArgumentError("wrong number of arguments(#{args.length} for 1)") unless args.length < 2
28
+ value = if block then ::LightConfig::Configuration.new(&block)
29
+ else args.first
30
+ end
31
+ @configuration.instance_variable_get(:@properties)[method] = value
32
+ end
33
+ end
34
+
35
+ class <<self
36
+ def build(&block)
37
+ LightConfig::Configuration.new(&block)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,404 @@
1
+ gem 'solr-ruby'
2
+ require 'solr'
3
+ require File.join(File.dirname(__FILE__), 'light_config')
4
+
5
+ %w(adapters configuration setup field data_extractor indexer
6
+ query search facet facet_row session type util dsl).each do |filename|
7
+ require File.join(File.dirname(__FILE__), 'sunspot', filename)
8
+ end
9
+
10
+ #
11
+ # The Sunspot module provides class-method entry points to most of the
12
+ # functionality provided by the Sunspot library. Internally, the Sunspot
13
+ # singleton class contains a (non-thread-safe!) instance of Sunspot::Session,
14
+ # to which it delegates most of the class methods it exposes. In the method
15
+ # documentation below, this instance is referred to as the "singleton session".
16
+ #
17
+ # Though the singleton session provides a convenient entry point to Sunspot,
18
+ # it is by no means required to use the Sunspot class methods. Multiple sessions
19
+ # may be instantiated and used (if you need to connect to multiple Solr
20
+ # instances, for example.)
21
+ #
22
+ # Note that the configuration of classes for index/search (the +setup+
23
+ # method) is _not_ session-specific, but rather global.
24
+ #
25
+ module Sunspot
26
+ UnrecognizedFieldError = Class.new(Exception)
27
+ UnrecognizedRestrictionError = Class.new(Exception)
28
+ NoAdapterError = Class.new(Exception)
29
+ NoSetupError = Class.new(Exception)
30
+
31
+ class <<self
32
+ # Configures indexing and search for a given class.
33
+ #
34
+ # ==== Parameters
35
+ #
36
+ # clazz<Class>:: class to configure
37
+ #
38
+ # ==== Example
39
+ #
40
+ # Sunspot.setup(Post) do
41
+ # text :title, :body
42
+ # string :author_name
43
+ # integer :blog_id
44
+ # integer :category_ids
45
+ # float :average_rating, :using => :ratings_average
46
+ # time :published_at
47
+ # string :sort_title do
48
+ # title.downcase.sub(/^(an?|the)\W+/, ''/) if title = self.title
49
+ # end
50
+ # end
51
+ #
52
+ # ====== Attribute Fields vs. Virtual Fields
53
+ #
54
+ # Attribute fields call a method on the indexed object and index the
55
+ # return value. All of the fields defined above except for the last one are
56
+ # attribute fields. By default, the field name will also be the attribute
57
+ # used; this can be overriden with the +:using+ option, as in
58
+ # +:average_rating+ above. In that case, the attribute +:ratings_average+
59
+ # will be indexed with the field name +:average_rating+.
60
+ #
61
+ # +:sort_title+ is a virtual field, which evaluates the block inside the
62
+ # context of the instance being indexed, and indexes the value returned
63
+ # by the block. If the block you pass takes an argument, it will be passed
64
+ # the instance rather than being evaluated inside of it; so, the following
65
+ # example is equivalent to the one above (assuming #title is public):
66
+ #
67
+ # Sunspot.setup(Post) do
68
+ # string :sort_title do |post|
69
+ # post.title.downcase.sub(/^(an?|the)\W+/, ''/) if title = self.title
70
+ # end
71
+ # end
72
+ #
73
+ # ===== Field Types
74
+ #
75
+ # The available types are:
76
+ #
77
+ # * +text+
78
+ # * +string+
79
+ # * +integer+
80
+ # * +float+
81
+ # * +time+
82
+ # * +boolean+
83
+ #
84
+ # Note that the +text+ type behaves quite differently from the others -
85
+ # this is the type that is indexed as fulltext, and is searched using the
86
+ # +keywords+ method inside the search DSL. Text fields cannot have
87
+ # restrictions set on them, nor can they be used in order statements or
88
+ # for facets. All other types are indexed literally, and thus can be used
89
+ # for all of those operations. They will not, however, be searched in
90
+ # fulltext. In this way, Sunspot provides a complete barrier between
91
+ # fulltext fields and value fields.
92
+ #
93
+ # It is fine to specify a field both as a text field and a string field;
94
+ # internally, the fields will have different names so there is no danger
95
+ # of conflict.
96
+ #
97
+ # ===== Dynamic Fields
98
+ #
99
+ # For use cases which have highly dynamic data models (for instance, an
100
+ # open set of key-value pairs attached to a model), it may be useful to
101
+ # defer definition of fields until indexing time. Sunspot exposes dynamic
102
+ # fields, which define a data accessor (either attribute or virtual, see
103
+ # above), which accepts a hash of field names to values. Note that the field
104
+ # names in the hash are internally scoped to the base name of the dynamic
105
+ # field, so any time they are referred to, they are referred to using both
106
+ # the base name and the dynamic (runtime-specified) name.
107
+ #
108
+ # Dynamic fields are speficied in the setup block using the type name
109
+ # prefixed by +dynamic_+. For example:
110
+ #
111
+ # Sunspot.setup(Post) do
112
+ # dynamic_string :custom_values do
113
+ # key_value_pairs.inject({}) do |hash, key_value_pair|
114
+ # hash[key_value_pair.key.to_sym] = key_value_pair.value
115
+ # end
116
+ # end
117
+ # end
118
+ #
119
+ # If you later wanted to facet all of the values for the key "cuisine",
120
+ # you could issue:
121
+ #
122
+ # Sunspot.search(Post) do
123
+ # dynamic :custom_values do
124
+ # facet :cuisine
125
+ # end
126
+ # end
127
+ #
128
+ # In the documentation, +:custom_values+ is referred to as the "base name" -
129
+ # that is, the one specified statically - and +:cuisine+ is referred to as
130
+ # the dynamic name, which is the part that is specified at indexing time.
131
+ #
132
+ def setup(clazz, &block)
133
+ Setup.setup(clazz, &block)
134
+ end
135
+
136
+ # Indexes objects on the singleton session.
137
+ #
138
+ # ==== Parameters
139
+ #
140
+ # objects...<Object>:: objects to index (may pass an array or varargs)
141
+ #
142
+ # ==== Example
143
+ #
144
+ # post1, post2 = Array(2) { Post.create }
145
+ # Sunspot.index(post1, post2)
146
+ #
147
+ # Note that indexed objects won't be reflected in search until a commit is
148
+ # sent - see Sunspot.index! and Sunspot.commit
149
+ #
150
+ def index(*objects)
151
+ session.index(*objects)
152
+ end
153
+
154
+ # Indexes objects on the singleton session and commits immediately.
155
+ #
156
+ # See: Sunspot.index and Sunspot.commit
157
+ #
158
+ # ==== Parameters
159
+ #
160
+ # objects...<Object>:: objects to index (may pass an array or varargs)
161
+ #
162
+ def index!(*objects)
163
+ session.index!(*objects)
164
+ end
165
+
166
+ # Commits the singleton session
167
+ #
168
+ # When documents are added to or removed from Solr, the changes are
169
+ # initially stored in memory, and are not reflected in Solr's existing
170
+ # searcher instance. When a commit message is sent, the changes are written
171
+ # to disk, and a new searcher is spawned. Commits are thus fairly
172
+ # expensive, so if your application needs to index several documents as part
173
+ # of a single operation, it is advisable to index them all and then call
174
+ # commit at the end of the operation.
175
+ #
176
+ # Note that Solr can also be configured to automatically perform a commit
177
+ # after either a specified interval after the last change, or after a
178
+ # specified number of documents are added. See
179
+ # http://wiki.apache.org/solr/SolrConfigXml
180
+ #
181
+ def commit
182
+ session.commit
183
+ end
184
+
185
+ #
186
+ # Create a new Search instance, but do not execute it immediately. Generally
187
+ # you will want to use the #search method to execute searches using the
188
+ # DSL; however, if you are building searches dynamically (using the Builder
189
+ # pattern, for instance), it may be easier to access the Query API directly.
190
+ #
191
+ # ==== Parameters
192
+ #
193
+ # types<Class>...::
194
+ # Zero, one, or more types to search for. If no types are passed, all
195
+ # configured types will be searched for.
196
+ #
197
+ # ==== Returns
198
+ #
199
+ # Sunspot::Search::
200
+ # Search object, not yet executed. Query parameters can be added manually;
201
+ # then #execute! should be called.
202
+ #
203
+ def new_search(*types)
204
+ session.new_search(*types)
205
+ end
206
+
207
+
208
+ # Search for objects in the index.
209
+ #
210
+ # ==== Parameters
211
+ #
212
+ # types<Class>...::
213
+ # Zero, one, or more types to search for. If no types are passed, all
214
+ # configured types will be searched.
215
+ #
216
+ # ==== Options (last argument, optional)
217
+ #
218
+ # :keywords<String>:: Fulltext search string
219
+ # :conditions<Hash>::
220
+ # Hash of key-value pairs to be used as restrictions. Keys are field
221
+ # names. Scalar values are used as equality restrictions; arrays are used
222
+ # as "any of" restrictions; and Ranges are used as range restrictions.
223
+ # :order<String>:: order field and direction (e.g., 'updated_at desc')
224
+ # :page<Integer>:: Page to start on for pagination
225
+ # :per_page<Integer>::
226
+ # Number of results to use per page. Ignored if :page is not specified.
227
+ #
228
+ # ==== Returns
229
+ #
230
+ # Sunspot::Search:: Object containing results, facets, count, etc.
231
+ #
232
+ # The fields available for restriction, ordering, etc. are those that meet
233
+ # the following criteria:
234
+ #
235
+ # * They are not of type +text+.
236
+ # * They are defined for all of the classes being searched
237
+ # * They have the same data type for all of the classes being searched
238
+ # * They have the same multiple flag for all of the classes being searched.
239
+ #
240
+ # The restrictions available are the constants defined in the
241
+ # Sunspot::Restriction class. The standard restrictions are:
242
+ #
243
+ # with(:field_name).equal_to(value)
244
+ # with(:field_name, value) # shorthand for above
245
+ # with(:field_name).less_than(value)
246
+ # with(:field_name).greater_than(value)
247
+ # with(:field_name).between(value1..value2)
248
+ # with(:field_name).any_of([value1, value2, value3])
249
+ # with(:field_name).all_of([value1, value2, value3])
250
+ # without(some_instance) # exclude that particular instance
251
+ #
252
+ # +without+ can be substituted for +with+, causing the restriction to be
253
+ # negated. In the last example above, only +without+ works, as it does not
254
+ # make sense to search only for an instance you already have.
255
+ #
256
+ # Equality restrictions can take +nil+ as a value, which restricts the
257
+ # results to documents that have no value for the given field. Passing +nil+
258
+ # as a value to other restriction types is illegal. Thus:
259
+ #
260
+ # with(:field_name, nil) # ok
261
+ # with(:field_name).equal_to(nil) # ok
262
+ # with(:field_name).less_than(nil) # bad
263
+ #
264
+ # ==== Example
265
+ #
266
+ # Sunspot.search(Post) do
267
+ # keywords 'great pizza'
268
+ # with(:published_at).less_than Time.now
269
+ # with :blog_id, 1
270
+ # without current_post
271
+ # facet :category_ids
272
+ # order_by :published_at, :desc
273
+ # paginate 2, 15
274
+ # end
275
+ #
276
+ # If the block passed to #search takes an argument, that argument will
277
+ # present the DSL, and the block will be evaluated in the calling context.
278
+ # This will come in handy for building searches using instance data or
279
+ # methods, e.g.:
280
+ #
281
+ # Sunspot.search(Post) do |query|
282
+ # query.with(:blog_id, @current_blog.id)
283
+ # end
284
+ #
285
+ # See Sunspot::DSL::Scope and Sunspot::DSL::Query for the full API presented
286
+ # inside the block.
287
+ #
288
+ def search(*types, &block)
289
+ session.search(*types, &block)
290
+ end
291
+
292
+ # Remove objects from the index. Any time an object is destroyed, it must
293
+ # be removed from the index; otherwise, the index will contain broken
294
+ # references to objects that do not exist, which will cause errors when
295
+ # those objects are matched in search results.
296
+ #
297
+ # ==== Parameters
298
+ #
299
+ # objects...<Object>::
300
+ # Objects to remove from the index (may pass an array or varargs)
301
+ #
302
+ # ==== Example
303
+ #
304
+ # post.destroy
305
+ # Sunspot.remove(post)
306
+ #
307
+ def remove(*objects)
308
+ session.remove(*objects)
309
+ end
310
+
311
+ #
312
+ # Remove objects from the index and immediately commit. See Sunspot.remove
313
+ #
314
+ # ==== Parameters
315
+ #
316
+ # objects...<Object>:: Objects to remove from the index
317
+ #
318
+ def remove!
319
+ session.remove!(*objects)
320
+ end
321
+
322
+ # Remove all objects of the given classes from the index. There isn't much
323
+ # use for this in general operations but it can be useful for maintenance,
324
+ # testing, etc. If no arguments are passed, remove everything from the
325
+ # index.
326
+ #
327
+ # ==== Parameters
328
+ #
329
+ # classes...<Class>::
330
+ # classes for which to remove all instances from the index (may pass an
331
+ # array or varargs)
332
+ #
333
+ # ==== Example
334
+ #
335
+ # Sunspot.remove_all(Post, Blog)
336
+ #
337
+ def remove_all(*classes)
338
+ session.remove_all(*classes)
339
+ end
340
+
341
+ #
342
+ # Remove all objects of the given classes from the index and immediately
343
+ # commit. See Sunspot.remove_all
344
+ #
345
+ # ==== Parameters
346
+ #
347
+ # classes...<Class>::
348
+ # classes for which to remove all instances from the index
349
+ def remove_all!(*classes)
350
+ session.remove_all(*classes)
351
+ end
352
+
353
+ #
354
+ # True if documents have been added, updated, or removed since the last
355
+ # commit.
356
+ #
357
+ # ==== Returns
358
+ #
359
+ # Boolean:: Whether there have been any updates since the last commit
360
+ #
361
+ def dirty?
362
+ session.dirty?
363
+ end
364
+
365
+ #
366
+ # Sends a commit if the session is dirty (see #dirty?).
367
+ #
368
+ def commit_if_dirty
369
+ session.commit_if_dirty
370
+ end
371
+
372
+ # Returns the configuration associated with the singleton session. See
373
+ # Sunspot::Configuration for details.
374
+ #
375
+ # ==== Returns
376
+ #
377
+ # LightConfig::Configuration:: configuration for singleton session
378
+ #
379
+ def config
380
+ session.config
381
+ end
382
+
383
+ #
384
+ # Resets the singleton session. This is useful for clearing out all
385
+ # static data between tests, but probably nowhere else.
386
+ #
387
+ def reset!
388
+ @session = nil
389
+ end
390
+
391
+ private
392
+
393
+ #
394
+ # Get the singleton session, creating it if none yet exists.
395
+ #
396
+ # ==== Returns
397
+ #
398
+ # Sunspot::Session:: the singleton session
399
+ #
400
+ def session #:nodoc:
401
+ @session ||= Session.new
402
+ end
403
+ end
404
+ end