outoftime-sunspot 0.8.9 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/README.rdoc +13 -21
  2. data/Rakefile +0 -2
  3. data/TODO +2 -15
  4. data/VERSION.yml +2 -2
  5. data/bin/sunspot-configure-solr +46 -0
  6. data/bin/sunspot-solr +15 -7
  7. data/lib/sunspot/adapters.rb +5 -1
  8. data/lib/sunspot/composite_setup.rb +186 -0
  9. data/lib/sunspot/configuration.rb +7 -1
  10. data/lib/sunspot/data_extractor.rb +10 -0
  11. data/lib/sunspot/date_facet.rb +36 -0
  12. data/lib/sunspot/date_facet_row.rb +17 -0
  13. data/lib/sunspot/dsl/field_query.rb +72 -0
  14. data/lib/sunspot/dsl/fields.rb +30 -3
  15. data/lib/sunspot/dsl/query.rb +16 -35
  16. data/lib/sunspot/dsl/query_facet.rb +31 -0
  17. data/lib/sunspot/dsl/scope.rb +76 -20
  18. data/lib/sunspot/dsl/search.rb +30 -0
  19. data/lib/sunspot/dsl.rb +1 -1
  20. data/lib/sunspot/facet.rb +17 -3
  21. data/lib/sunspot/facet_row.rb +4 -4
  22. data/lib/sunspot/field.rb +130 -207
  23. data/lib/sunspot/field_factory.rb +126 -0
  24. data/lib/sunspot/indexer.rb +61 -14
  25. data/lib/sunspot/instantiated_facet.rb +38 -0
  26. data/lib/sunspot/instantiated_facet_row.rb +12 -0
  27. data/lib/sunspot/query/base_query.rb +90 -0
  28. data/lib/sunspot/query/connective.rb +77 -0
  29. data/lib/sunspot/query/dynamic_query.rb +39 -56
  30. data/lib/sunspot/query/field_facet.rb +132 -4
  31. data/lib/sunspot/query/field_query.rb +57 -0
  32. data/lib/sunspot/query/pagination.rb +1 -1
  33. data/lib/sunspot/query/query_facet.rb +72 -0
  34. data/lib/sunspot/query/query_facet_row.rb +19 -0
  35. data/lib/sunspot/query/restriction.rb +9 -7
  36. data/lib/sunspot/query/scope.rb +165 -0
  37. data/lib/sunspot/query/sort.rb +17 -14
  38. data/lib/sunspot/query/sort_composite.rb +33 -0
  39. data/lib/sunspot/query.rb +162 -351
  40. data/lib/sunspot/query_facet.rb +33 -0
  41. data/lib/sunspot/query_facet_row.rb +21 -0
  42. data/lib/sunspot/schema.rb +165 -0
  43. data/lib/sunspot/search/hit.rb +62 -0
  44. data/lib/sunspot/search.rb +104 -41
  45. data/lib/sunspot/session.rb +64 -32
  46. data/lib/sunspot/setup.rb +119 -48
  47. data/lib/sunspot/type.rb +48 -2
  48. data/lib/sunspot.rb +74 -8
  49. data/solr/solr/conf/schema.xml +44 -225
  50. data/spec/api/build_search_spec.rb +557 -63
  51. data/spec/api/indexer_spec.rb +156 -74
  52. data/spec/api/query_spec.rb +55 -31
  53. data/spec/api/search_retrieval_spec.rb +210 -33
  54. data/spec/api/session_spec.rb +81 -26
  55. data/spec/api/sunspot_spec.rb +5 -7
  56. data/spec/integration/faceting_spec.rb +130 -0
  57. data/spec/integration/keyword_search_spec.rb +72 -31
  58. data/spec/integration/scoped_search_spec.rb +13 -0
  59. data/spec/integration/stored_fields_spec.rb +10 -0
  60. data/spec/mocks/blog.rb +3 -0
  61. data/spec/mocks/comment.rb +12 -23
  62. data/spec/mocks/connection.rb +84 -0
  63. data/spec/mocks/mock_adapter.rb +11 -3
  64. data/spec/mocks/mock_record.rb +41 -0
  65. data/spec/mocks/photo.rb +8 -0
  66. data/spec/mocks/post.rb +18 -23
  67. data/spec/spec_helper.rb +29 -14
  68. data/tasks/gemspec.rake +4 -3
  69. data/tasks/rdoc.rake +2 -2
  70. data/tasks/schema.rake +19 -0
  71. data/templates/schema.xml.haml +24 -0
  72. metadata +48 -7
  73. data/spec/mocks/base_class.rb +0 -2
@@ -1,42 +1,83 @@
1
1
  require File.join(File.dirname(__FILE__), 'spec_helper')
2
2
 
3
3
  describe 'keyword search' do
4
- before :all do
5
- Sunspot.remove_all
6
- @posts = []
7
- @posts << Post.new(:title => 'The toast elects the insufficient spirit',
8
- :body => 'Does the wind write?')
9
- @posts << Post.new(:title => 'A nail abbreviates the recovering insight outside the moron',
10
- :body => 'The interpreted strain scans the buffer around the upper temper')
11
- @posts << Post.new(:title => 'The toast abbreviates the recovering spirit',
12
- :body => 'Does the wind interpret the buffer?')
13
- Sunspot.index!(*@posts)
14
- @comment = Namespaced::Comment.new(:body => 'Hey there where ya goin, not exactly knowin, who says you have to call just one place toast.')
15
- Sunspot.index!(@comment)
16
- end
4
+ describe 'generally' do
5
+ before :all do
6
+ Sunspot.remove_all
7
+ @posts = []
8
+ @posts << Post.new(:title => 'The toast elects the insufficient spirit',
9
+ :body => 'Does the wind write?')
10
+ @posts << Post.new(:title => 'A nail abbreviates the recovering insight outside the moron',
11
+ :body => 'The interpreted strain scans the buffer around the upper temper')
12
+ @posts << Post.new(:title => 'The toast abbreviates the recovering spirit',
13
+ :body => 'Does the wind interpret the buffer, moron?')
14
+ Sunspot.index!(*@posts)
15
+ @comment = Namespaced::Comment.new(:body => 'Hey there where ya goin, not exactly knowin, who says you have to call just one place toast.')
16
+ Sunspot.index!(@comment)
17
+ end
17
18
 
18
- it 'matches a single keyword out of a single field' do
19
- results = Sunspot.search(Post) { keywords 'toast' }.results
20
- [0, 2].each { |i| results.should include(@posts[i]) }
21
- [1].each { |i| results.should_not include(@posts[i]) }
22
- end
19
+ it 'matches a single keyword out of a single field' do
20
+ results = Sunspot.search(Post) { keywords 'toast' }.results
21
+ [0, 2].each { |i| results.should include(@posts[i]) }
22
+ [1].each { |i| results.should_not include(@posts[i]) }
23
+ end
24
+
25
+ it 'matches multiple words out of a single field' do
26
+ results = Sunspot.search(Post) { keywords 'elects toast' }.results
27
+ results.should == [@posts[0]]
28
+ end
29
+
30
+ it 'matches multiple words in multiple fields' do
31
+ results = Sunspot.search(Post) { keywords 'toast wind' }.results
32
+ [0, 2].each { |i| results.should include(@posts[i]) }
33
+ [1].each { |i| results.should_not include(@posts[i]) }
34
+ end
23
35
 
24
- it 'matches multiple words out of a single field' do
25
- results = Sunspot.search(Post) { keywords 'elects toast' }.results
26
- results.should == [@posts[0]]
36
+ it 'matches multiple types' do
37
+ results = Sunspot.search(Post, Namespaced::Comment) do
38
+ keywords 'toast'
39
+ end.results
40
+ [@posts[0], @posts[2], @comment].each { |obj| results.should include(obj) }
41
+ results.should_not include(@posts[1])
42
+ end
43
+
44
+ it 'matches keywords from only the fields specified' do
45
+ results = Sunspot.search(Post) do
46
+ keywords 'moron', :fields => [:title]
47
+ end.results
48
+ results.should == [@posts[1]]
49
+ end
27
50
  end
28
51
 
29
- it 'matches multiple words in multiple fields' do
30
- results = Sunspot.search(Post) { keywords 'toast wind' }.results
31
- [0, 2].each { |i| results.should include(@posts[i]) }
32
- [1].each { |i| results.should_not include(@posts[i]) }
52
+ describe 'with field boost' do
53
+ before :all do
54
+ Sunspot.remove_all
55
+ @posts = [:title, :body].map { |field| Post.new(field => 'rhinoceros') }
56
+ Sunspot.index!(*@posts)
57
+ end
58
+
59
+ it 'should assign a higher score to the result matching the higher-boosted field' do
60
+ search = Sunspot.search(Post) { keywords 'rhinoceros' }
61
+ search.hits.map { |hit| hit.primary_key }.should ==
62
+ @posts.map { |post| post.id.to_s }
63
+ search.hits.first.score.should > search.hits.last.score
64
+ end
33
65
  end
34
66
 
35
- it 'matches multiple types' do
36
- results = Sunspot.search(Post, Namespaced::Comment) do
37
- keywords 'toast'
38
- end.results
39
- [@posts[0], @posts[2], @comment].each { |obj| results.should include(obj) }
40
- results.should_not include(@posts[1])
67
+ describe 'with document boost' do
68
+ before :all do
69
+ Sunspot.remove_all
70
+ @posts = [4.0, 2.0].map do |rating|
71
+ Post.new(:title => 'Test', :ratings_average => rating)
72
+ end
73
+ Sunspot.index!(*@posts)
74
+ end
75
+
76
+ it 'should assign a higher score to the higher-boosted document' do
77
+ search = Sunspot.search(Post) { keywords 'test' }
78
+ search.hits.map { |hit| hit.primary_key }.should ==
79
+ @posts.map { |post| post.id.to_s }
80
+ search.hits.first.score.should > search.hits.last.score
81
+ end
41
82
  end
42
83
  end
@@ -172,4 +172,17 @@ describe 'scoped_search' do
172
172
  search.results.should == @posts
173
173
  end
174
174
  end
175
+
176
+ describe 'ordering by random' do
177
+ it 'should order randomly (run this test again if it fails)' do
178
+ Sunspot.remove_all
179
+ Sunspot.index!(Array.new(100) { Post.new })
180
+ result_sets = Array.new(2) do
181
+ Sunspot.search(Post) { order_by_random }.results.map do |result|
182
+ result.id
183
+ end
184
+ end
185
+ result_sets[0].should_not == result_sets[1]
186
+ end
187
+ end
175
188
  end
@@ -0,0 +1,10 @@
1
+ describe 'stored fields' do
2
+ before :all do
3
+ Sunspot.remove_all
4
+ Sunspot.index!(Post.new(:title => 'A Title'))
5
+ end
6
+
7
+ it 'should return stored fields' do
8
+ Sunspot.search(Post).hits.first.stored(:title).should == 'A Title'
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ class Blog < MockRecord
2
+ attr_accessor :name
3
+ end
@@ -1,30 +1,19 @@
1
1
  module Namespaced
2
- class Comment < BaseClass
3
- @@id = 0
4
- @@comments = [nil]
5
-
2
+ class Comment < MockRecord
6
3
  attr_reader :id
7
- attr_accessor :author_name, :published_at, :body, :average_rating
8
-
9
- def initialize(attrs = {})
10
- @id = @@id += 1
11
- @@comments << self
12
- attrs.each_pair { |attribute, value| self.send("#{attribute}=", value) }
13
- end
4
+ attr_accessor :author_name, :published_at, :body, :average_rating, :boost
14
5
 
15
- def self.get(id)
16
- @@comments[id]
17
- end
18
-
19
- def self.get_all(ids)
20
- ids.map { |id| get(id) }.sort_by { |post| post.id } # this is so that results are not ordered by coincidence
6
+ def custom_string
7
+ @custom_string ||= {}
21
8
  end
22
9
  end
10
+ end
23
11
 
24
- Sunspot.setup(Comment) do
25
- text :author_name, :body
26
- string :author_name
27
- time :published_at
28
- integer :average_rating
29
- end
12
+ Sunspot.setup(Namespaced::Comment) do
13
+ text :body, :author_name
14
+ string :author_name
15
+ time :published_at
16
+ integer :average_rating
17
+ dynamic_string :custom_string
18
+ boost :boost
30
19
  end
@@ -0,0 +1,84 @@
1
+ module Mock
2
+ class ConnectionFactory
3
+ def new(adapter = nil, opts = nil)
4
+ if @instance
5
+ raise('Factory can only create an instance once!')
6
+ else
7
+ @instance = Connection.new(adapter, opts)
8
+ end
9
+ end
10
+
11
+ def instance
12
+ @instance ||= Connection.new
13
+ end
14
+ end
15
+
16
+ class Connection
17
+ attr_reader :adds, :commits, :searches
18
+ attr_accessor :adapter, :opts
19
+
20
+ def initialize(adapter = nil, opts = nil)
21
+ @adapter, @opts = adapter, opts
22
+ @adds, @deletes, @deletes_by_query, @commits, @searches = Array.new(5) { [] }
23
+ end
24
+
25
+ def add(documents)
26
+ @adds << Array(documents)
27
+ end
28
+
29
+ def delete_by_id(*ids)
30
+ @deletes << ids
31
+ end
32
+
33
+ def delete_by_query(query)
34
+ @deletes_by_query << query
35
+ end
36
+
37
+ def commit
38
+ @commits << Time.now
39
+ end
40
+
41
+ def select(params)
42
+ @searches << @last_search = params
43
+ end
44
+
45
+ def has_add_with?(*documents)
46
+ @adds.any? do |add|
47
+ documents.all? do |document|
48
+ add.any? do |added|
49
+ if document.is_a?(Hash)
50
+ document.all? do |field, value|
51
+ added.fields_by_name(field).map do |field|
52
+ field.value
53
+ end == Array(value)
54
+ end
55
+ else
56
+ !added.fields_by_name(document).empty?
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ def has_delete?(*ids)
64
+ @deletes.any? do |delete|
65
+ delete & ids == ids
66
+ end
67
+ end
68
+
69
+ def has_delete_by_query?(query)
70
+ @deletes_by_query.include?(query)
71
+ end
72
+
73
+ def has_last_search_with?(params)
74
+ return unless @last_search
75
+ if params.respond_to?(:all?)
76
+ params.all? do |key, value|
77
+ @last_search.has_key?(key) && @last_search[key] == value
78
+ end
79
+ else
80
+ @last_search.has_key?(params)
81
+ end
82
+ end
83
+ end
84
+ end
@@ -13,10 +13,18 @@ module MockAdapter
13
13
  end
14
14
 
15
15
  def load_all(ids)
16
- @clazz.get_all(ids.map { |id| id.to_i })
16
+ all = @clazz.get_all(ids.map { |id| id.to_i })
17
+ if @custom_title
18
+ all.each { |item| item.title = @custom_title }
19
+ end
20
+ all
21
+ end
22
+
23
+ def custom_title=(custom_title)
24
+ @custom_title = custom_title
17
25
  end
18
26
  end
19
27
  end
20
28
 
21
- Sunspot::Adapters::DataAccessor.register(MockAdapter::DataAccessor, BaseClass)
22
- Sunspot::Adapters::InstanceAdapter.register(MockAdapter::InstanceAdapter, BaseClass)
29
+ Sunspot::Adapters::DataAccessor.register(MockAdapter::DataAccessor, MockRecord)
30
+ Sunspot::Adapters::InstanceAdapter.register(MockAdapter::InstanceAdapter, MockRecord)
@@ -0,0 +1,41 @@
1
+ class MockRecord
2
+ IDS = Hash.new { |h, k| h[k] = 0 }
3
+ QUERY_COUNTS = Hash.new { |h, k| h[k] = 0 }
4
+ INSTANCES = Hash.new { |h, k| h[k] = {} }
5
+
6
+ attr_reader :id
7
+
8
+ def initialize(attrs = {})
9
+ attrs.each_pair do |name, value|
10
+ send(:"#{name}=", value)
11
+ end
12
+ @id = IDS[self.class.name.to_sym] += 1
13
+ INSTANCES[self.class.name.to_sym][@id] = self
14
+ end
15
+
16
+ def self.inherited(base)
17
+ base.extend(ClassMethods)
18
+ end
19
+
20
+ module ClassMethods
21
+ def get(id)
22
+ QUERY_COUNTS[self.name.to_sym] += 1
23
+ get_instance(id)
24
+ end
25
+
26
+ def get_all(ids)
27
+ QUERY_COUNTS[self.name.to_sym] += 1
28
+ ids.map { |id| get_instance(id) }.sort_by { |instance| instance.id }
29
+ end
30
+
31
+ def query_count
32
+ QUERY_COUNTS[self.name.to_sym]
33
+ end
34
+
35
+ private
36
+
37
+ def get_instance(id)
38
+ INSTANCES[self.name.to_sym][id]
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,8 @@
1
+ class Photo < MockRecord
2
+ attr_accessor :caption
3
+ end
4
+
5
+ Sunspot.setup(Photo) do
6
+ text :caption
7
+ boost 0.75
8
+ end
data/spec/mocks/post.rb CHANGED
@@ -1,30 +1,14 @@
1
- class Post < BaseClass
2
- @@id = 0
3
- @@posts = [nil]
1
+ require File.join(File.dirname(__FILE__), 'blog')
4
2
 
5
- attr_reader :id
6
- attr_accessor :title, :body, :blog_id, :published_at, :ratings_average, :author_name, :featured
3
+ class Post < MockRecord
4
+ attr_accessor :title, :body, :blog_id, :published_at, :ratings_average,
5
+ :author_name, :featured, :expire_date
7
6
  alias_method :featured?, :featured
8
7
 
9
-
10
- def initialize(attrs = {})
11
- @id = @@id += 1
12
- @@posts << self
13
- attrs.each_pair { |attribute, value| self.send "#{attribute}=", value }
14
- end
15
-
16
8
  def category_ids
17
9
  @category_ids ||= []
18
10
  end
19
11
 
20
- def self.get(id)
21
- @@posts[id]
22
- end
23
-
24
- def self.get_all(ids)
25
- ids.map { |id| get(id) }.sort_by { |post| post.id } # this is so that results are not ordered by coincidence
26
- end
27
-
28
12
  def custom_string
29
13
  @custom_string ||= {}
30
14
  end
@@ -46,15 +30,17 @@ class Post < BaseClass
46
30
  end
47
31
 
48
32
  Sunspot.setup(Post) do
49
- text :title, :body
33
+ text :title, :boost => 2
34
+ text :body
50
35
  text :backwards_title do
51
36
  title.reverse if title
52
37
  end
53
- string :title
54
- integer :blog_id
38
+ string :title, :stored => true
39
+ integer :blog_id, :references => Blog
55
40
  integer :category_ids, :multiple => true
56
41
  float :average_rating, :using => :ratings_average
57
42
  time :published_at
43
+ date :expire_date
58
44
  boolean :featured, :using => :featured?
59
45
  string :sort_title do
60
46
  title.downcase.sub(/^(a|an|the)\W+/, '') if title
@@ -62,6 +48,9 @@ Sunspot.setup(Post) do
62
48
  integer :primary_category_id do |post|
63
49
  post.category_ids.first
64
50
  end
51
+ time :last_indexed_at, :stored => true do
52
+ Time.now
53
+ end
65
54
 
66
55
  dynamic_string :custom_string
67
56
  dynamic_float :custom_float, :multiple => true, :using => :custom_fl
@@ -72,4 +61,10 @@ Sunspot.setup(Post) do
72
61
  end
73
62
  dynamic_time :custom_time
74
63
  dynamic_boolean :custom_boolean
64
+
65
+ boost do
66
+ if ratings_average
67
+ 1 + (ratings_average - 3.0) / 4.0
68
+ end
69
+ end
75
70
  end
data/spec/spec_helper.rb CHANGED
@@ -1,19 +1,32 @@
1
- require 'rubygems'
2
- gem 'mislav-will_paginate', '~> 2.3'
3
- gem 'rspec', '~> 1.1'
1
+ using_gems = false
4
2
  begin
5
- gem 'ruby-debug', '~>0.10'
6
- require 'ruby-debug'
7
- rescue Gem::LoadError
8
- module Kernel
9
- def debugger
10
- raise("debugger is not available")
3
+ require 'spec'
4
+ begin
5
+ require 'ruby-debug'
6
+ rescue LoadError => e
7
+ if using_gems
8
+ module Kernel
9
+ def debugger
10
+ STDERR.puts('Debugger is not available')
11
+ end
12
+ end
13
+ else
14
+ raise(e)
11
15
  end
12
16
  end
17
+ if ENV['USE_WILL_PAGINATE']
18
+ require 'will_paginate'
19
+ require 'will_paginate/collection'
20
+ end
21
+ rescue LoadError => e
22
+ require 'rubygems'
23
+ if using_gems
24
+ raise(e)
25
+ else
26
+ using_gems = true
27
+ retry
28
+ end
13
29
  end
14
- require 'spec'
15
- require 'will_paginate'
16
- require 'will_paginate/collection'
17
30
 
18
31
  unless gem_name = ENV['SUNSPOT_TEST_GEM']
19
32
  $:.unshift(File.dirname(__FILE__) + '/../lib')
@@ -22,8 +35,10 @@ else
22
35
  end
23
36
  require 'sunspot'
24
37
 
25
- require File.join(File.dirname(__FILE__), 'mocks', 'base_class.rb')
26
- Dir.glob(File.join(File.dirname(__FILE__), 'mocks', '**', '*.rb')).each { |file| require file }
38
+ require File.join(File.dirname(__FILE__), 'mocks', 'mock_record.rb')
39
+ Dir.glob(File.join(File.dirname(__FILE__), 'mocks', '**', '*.rb')).each do |file|
40
+ require file unless File.basename(file) == 'mock_record.rb'
41
+ end
27
42
 
28
43
  def without_class(clazz)
29
44
  Object.class_eval { remove_const(clazz.name.to_sym) }
data/tasks/gemspec.rake CHANGED
@@ -9,15 +9,16 @@ begin
9
9
  s.homepage = 'http://github.com/outoftime/sunspot'
10
10
  s.description = 'Library for expressive, powerful interaction with the Solr search engine'
11
11
  s.authors = ['Mat Brown', 'Peer Allan', 'Dmitriy Dzema', 'Benjamin Krause']
12
- s.files = FileList['[A-Z]*', '{bin,lib,spec,tasks}/**/*', 'solr/{etc,lib,webapps}/**/*', 'solr/solr/conf/*', 'solr/start.jar']
13
- s.add_dependency 'solr-ruby', '>= 0.0.6'
12
+ s.files = FileList['[A-Z]*', '{bin,lib,spec,tasks,templates}/**/*', 'solr/{etc,lib,webapps}/**/*', 'solr/solr/conf/*', 'solr/start.jar']
13
+ s.add_dependency 'mwmichell-rsolr', '>= 0.8.9'
14
14
  s.add_dependency 'daemons', '~> 1.0'
15
15
  s.add_dependency 'optiflag', '~> 0.6.5'
16
+ s.add_dependency 'haml', '~> 2.2'
16
17
  s.add_development_dependency 'rspec', '~> 1.1'
17
18
  s.add_development_dependency 'ruby-debug', '~> 0.10'
18
19
  s.extra_rdoc_files = ['README.rdoc']
19
20
  s.rdoc_options << '--webcvs=http://github.com/outoftime/sunspot/tree/master/%s' <<
20
- '--title' << 'Sunspot - Pure-Ruby Solr Search and Indexing - API Documentation' <<
21
+ '--title' << 'Sunspot - Solr-powered search for Ruby objects - API Documentation' <<
21
22
  '--main' << 'README.rdoc'
22
23
 
23
24
  end
data/tasks/rdoc.rake CHANGED
@@ -3,11 +3,11 @@ require 'hanna/rdoctask'
3
3
 
4
4
  Rake::RDocTask.new(:doc) do |rdoc|
5
5
  version = Jeweler::VersionHelper.new(File.join(File.dirname(__FILE__), '..')).to_s
6
- rdoc.title = 'Sunspot - Pure-Ruby Solr Search and Indexing - API Documentation'
6
+ rdoc.title = "Sunspot #{version} - Solr-powered search for Ruby objects - API Documentation"
7
7
  rdoc.main = 'README.rdoc'
8
8
  rdoc.rdoc_files.include('README.rdoc', 'lib/sunspot.rb', 'lib/sunspot/**/*.rb')
9
9
  rdoc.rdoc_dir = 'doc'
10
- rdoc.options << "--webcvs=http://github.com/outoftime/sunspot/tree/v#{version}/%s" << '--title' << 'Sunspot - Pure-Ruby Solr Search and Indexing - API Documentation'
10
+ rdoc.options << "--webcvs=http://github.com/outoftime/sunspot/tree/v#{version}/%s" << '--title' << 'Sunspot - Solr-powered search for Ruby objects - API Documentation'
11
11
  end
12
12
 
13
13
  namespace :doc do
data/tasks/schema.rake ADDED
@@ -0,0 +1,19 @@
1
+ namespace :schema do
2
+ desc 'Compile schema from Haml template'
3
+ task :compile do
4
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'sunspot', 'schema')
5
+ File.open(
6
+ File.join(
7
+ File.dirname(__FILE__),
8
+ '..',
9
+ 'solr',
10
+ 'solr',
11
+ 'conf',
12
+ 'schema.xml'
13
+ ),
14
+ 'w'
15
+ ) do |file|
16
+ file << Sunspot::Schema.new.to_xml
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ !!! XML
2
+ %schema{ :name => 'sunspot', :version => 0.9 }
3
+ %types
4
+ %fieldtype{ :name => 'text', :class => 'solr.TextField', :positionIncrementGap => 100 }
5
+ %analyzer
6
+ %tokenizer{ :class => schema.tokenizer }/
7
+ - for filter in schema.filters
8
+ %filter{ :class => filter }/
9
+ %fieldtype{ :name => 'rand', :class => 'solr.RandomSortField' }
10
+ - schema.types.each do |type|
11
+ %fieldtype{ :name => type.name, :class => "solr.#{type.class_name}Field", :omitNorms => 'true' }/
12
+ %fields
13
+ %field{ :name => 'id', :type => 'string', :indexed => 'true', :stored => 'true', :multiValued => 'false' }/
14
+ %field{ :name => 'type', :type => 'string', :indexed => 'true', :stored => 'false', :multiValued => 'true' }/
15
+ %field{ :name => 'class_name', :type => 'string', :indexed => 'true', :stored => 'false', :multiValued => 'false' }/
16
+ %field{ :name => 'text', :type => 'text', :indexed => 'true', :stored => 'false', :multiValued => 'true' }/
17
+ %dynamicField{ :name => '*_text', :type => 'text', :indexed => 'true', :stored => 'false', :multiValued => 'true' }/
18
+ %dynamicField{ :name => 'random_*', :type => 'rand', :indexed => 'true', :stored => 'false' }/
19
+ - for dynamic_field in schema.dynamic_fields
20
+ %dynamicField{ :name => dynamic_field.name, :type => dynamic_field.type, :indexed => 'true', :stored => dynamic_field.stored?, :multiValued => dynamic_field.multiValued? }/
21
+ %uniqueKey id
22
+ %defaultSearchField text
23
+ %solrQueryParser{ :defaultOperator => 'AND' }/
24
+ %copyField{ :source => '*_text', :dest => 'text' }/