nxa-sunspot 0.10.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. data/History.txt +153 -0
  2. data/LICENSE +18 -0
  3. data/README.rdoc +191 -0
  4. data/Rakefile +9 -0
  5. data/TODO +14 -0
  6. data/VERSION.yml +4 -0
  7. data/bin/sunspot-configure-solr +40 -0
  8. data/bin/sunspot-solr +95 -0
  9. data/lib/light_config.rb +40 -0
  10. data/lib/sunspot.rb +488 -0
  11. data/lib/sunspot/adapters.rb +265 -0
  12. data/lib/sunspot/composite_setup.rb +188 -0
  13. data/lib/sunspot/configuration.rb +56 -0
  14. data/lib/sunspot/data_extractor.rb +50 -0
  15. data/lib/sunspot/dsl.rb +4 -0
  16. data/lib/sunspot/dsl/field_query.rb +150 -0
  17. data/lib/sunspot/dsl/fields.rb +100 -0
  18. data/lib/sunspot/dsl/fulltext.rb +228 -0
  19. data/lib/sunspot/dsl/query.rb +162 -0
  20. data/lib/sunspot/dsl/query_facet.rb +36 -0
  21. data/lib/sunspot/dsl/restriction.rb +25 -0
  22. data/lib/sunspot/dsl/scope.rb +225 -0
  23. data/lib/sunspot/dsl/search.rb +30 -0
  24. data/lib/sunspot/field.rb +181 -0
  25. data/lib/sunspot/field_factory.rb +144 -0
  26. data/lib/sunspot/indexer.rb +133 -0
  27. data/lib/sunspot/query.rb +9 -0
  28. data/lib/sunspot/query/abstract_field_facet.rb +43 -0
  29. data/lib/sunspot/query/boost_query.rb +20 -0
  30. data/lib/sunspot/query/connective.rb +189 -0
  31. data/lib/sunspot/query/date_field_facet.rb +14 -0
  32. data/lib/sunspot/query/dismax.rb +88 -0
  33. data/lib/sunspot/query/field_facet.rb +9 -0
  34. data/lib/sunspot/query/highlighting.rb +55 -0
  35. data/lib/sunspot/query/local.rb +27 -0
  36. data/lib/sunspot/query/pagination.rb +38 -0
  37. data/lib/sunspot/query/query.rb +86 -0
  38. data/lib/sunspot/query/query_facet.rb +16 -0
  39. data/lib/sunspot/query/restriction.rb +254 -0
  40. data/lib/sunspot/query/scope.rb +9 -0
  41. data/lib/sunspot/query/sort.rb +105 -0
  42. data/lib/sunspot/query/sort_composite.rb +33 -0
  43. data/lib/sunspot/query/text_field_boost.rb +15 -0
  44. data/lib/sunspot/schema.rb +147 -0
  45. data/lib/sunspot/search.rb +216 -0
  46. data/lib/sunspot/search/date_facet.rb +35 -0
  47. data/lib/sunspot/search/facet_row.rb +27 -0
  48. data/lib/sunspot/search/field_facet.rb +44 -0
  49. data/lib/sunspot/search/highlight.rb +38 -0
  50. data/lib/sunspot/search/hit.rb +117 -0
  51. data/lib/sunspot/search/query_facet.rb +62 -0
  52. data/lib/sunspot/session.rb +236 -0
  53. data/lib/sunspot/setup.rb +323 -0
  54. data/lib/sunspot/text_field_setup.rb +29 -0
  55. data/lib/sunspot/type.rb +204 -0
  56. data/lib/sunspot/util.rb +210 -0
  57. data/solr/etc/jetty.xml +212 -0
  58. data/solr/etc/webdefault.xml +379 -0
  59. data/solr/lib/jetty-6.1.3.jar +0 -0
  60. data/solr/lib/jetty-util-6.1.3.jar +0 -0
  61. data/solr/lib/jsp-2.1/ant-1.6.5.jar +0 -0
  62. data/solr/lib/jsp-2.1/core-3.1.1.jar +0 -0
  63. data/solr/lib/jsp-2.1/jsp-2.1.jar +0 -0
  64. data/solr/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
  65. data/solr/lib/servlet-api-2.5-6.1.3.jar +0 -0
  66. data/solr/solr/conf/elevate.xml +36 -0
  67. data/solr/solr/conf/protwords.txt +21 -0
  68. data/solr/solr/conf/schema.xml +64 -0
  69. data/solr/solr/conf/solrconfig.xml +725 -0
  70. data/solr/solr/conf/stopwords.txt +57 -0
  71. data/solr/solr/conf/synonyms.txt +31 -0
  72. data/solr/solr/lib/geoapi-nogenerics-2.1-M2.jar +0 -0
  73. data/solr/solr/lib/gt2-referencing-2.3.1.jar +0 -0
  74. data/solr/solr/lib/jsr108-0.01.jar +0 -0
  75. data/solr/solr/lib/locallucene.jar +0 -0
  76. data/solr/solr/lib/localsolr.jar +0 -0
  77. data/solr/start.jar +0 -0
  78. data/solr/webapps/solr.war +0 -0
  79. data/spec/api/adapters_spec.rb +33 -0
  80. data/spec/api/indexer/attributes_spec.rb +110 -0
  81. data/spec/api/indexer/batch_spec.rb +46 -0
  82. data/spec/api/indexer/dynamic_fields_spec.rb +33 -0
  83. data/spec/api/indexer/fixed_fields_spec.rb +57 -0
  84. data/spec/api/indexer/fulltext_spec.rb +43 -0
  85. data/spec/api/indexer/removal_spec.rb +46 -0
  86. data/spec/api/indexer/spec_helper.rb +1 -0
  87. data/spec/api/indexer_spec.rb +4 -0
  88. data/spec/api/query/adjust_params_spec.rb +37 -0
  89. data/spec/api/query/connectives_spec.rb +176 -0
  90. data/spec/api/query/dsl_spec.rb +12 -0
  91. data/spec/api/query/dynamic_fields_spec.rb +149 -0
  92. data/spec/api/query/faceting_spec.rb +296 -0
  93. data/spec/api/query/fulltext_spec.rb +281 -0
  94. data/spec/api/query/highlighting_spec.rb +225 -0
  95. data/spec/api/query/local_spec.rb +62 -0
  96. data/spec/api/query/ordering_pagination_spec.rb +95 -0
  97. data/spec/api/query/scope_spec.rb +266 -0
  98. data/spec/api/query/spec_helper.rb +1 -0
  99. data/spec/api/query/text_field_scoping_spec.rb +30 -0
  100. data/spec/api/query/types_spec.rb +20 -0
  101. data/spec/api/search/dynamic_fields_spec.rb +27 -0
  102. data/spec/api/search/faceting_spec.rb +242 -0
  103. data/spec/api/search/highlighting_spec.rb +65 -0
  104. data/spec/api/search/hits_spec.rb +67 -0
  105. data/spec/api/search/results_spec.rb +52 -0
  106. data/spec/api/search/search_spec.rb +23 -0
  107. data/spec/api/search/spec_helper.rb +1 -0
  108. data/spec/api/session_spec.rb +198 -0
  109. data/spec/api/spec_helper.rb +1 -0
  110. data/spec/api/sunspot_spec.rb +18 -0
  111. data/spec/helpers/indexer_helper.rb +29 -0
  112. data/spec/helpers/query_helper.rb +13 -0
  113. data/spec/helpers/search_helper.rb +78 -0
  114. data/spec/integration/dynamic_fields_spec.rb +55 -0
  115. data/spec/integration/faceting_spec.rb +188 -0
  116. data/spec/integration/highlighting_spec.rb +22 -0
  117. data/spec/integration/indexing_spec.rb +7 -0
  118. data/spec/integration/keyword_search_spec.rb +245 -0
  119. data/spec/integration/local_search_spec.rb +56 -0
  120. data/spec/integration/scoped_search_spec.rb +303 -0
  121. data/spec/integration/spec_helper.rb +7 -0
  122. data/spec/integration/stored_fields_spec.rb +10 -0
  123. data/spec/integration/test_pagination.rb +32 -0
  124. data/spec/mocks/adapters.rb +32 -0
  125. data/spec/mocks/blog.rb +3 -0
  126. data/spec/mocks/comment.rb +19 -0
  127. data/spec/mocks/connection.rb +106 -0
  128. data/spec/mocks/mock_adapter.rb +30 -0
  129. data/spec/mocks/mock_record.rb +48 -0
  130. data/spec/mocks/photo.rb +11 -0
  131. data/spec/mocks/post.rb +75 -0
  132. data/spec/mocks/super_class.rb +2 -0
  133. data/spec/mocks/user.rb +8 -0
  134. data/spec/spec_helper.rb +68 -0
  135. data/tasks/gemspec.rake +42 -0
  136. data/tasks/rcov.rake +28 -0
  137. data/tasks/rdoc.rake +22 -0
  138. data/tasks/schema.rake +19 -0
  139. data/tasks/spec.rake +24 -0
  140. data/tasks/todo.rake +4 -0
  141. data/templates/schema.xml.erb +36 -0
  142. metadata +319 -0
@@ -0,0 +1,56 @@
1
+ module Sunspot
2
+ # The Sunspot::Configuration module provides a factory method for Sunspot
3
+ # configuration objects. Available properties are:
4
+ #
5
+ # Sunspot.config.http_client::
6
+ # The client to use for HTTP communication with Solr. Available options are
7
+ # :net_http, which is the default and uses Ruby's built-in pure-Ruby HTTP
8
+ # library; and :curb, which uses Ruby's libcurl bindings and requires
9
+ # installation of the 'curb' gem.
10
+ # Sunspot.config.xml_builder::
11
+ # The library use to build XML messages sent to Solr. As of this writing the
12
+ # options are :builder and :libxml - the latter is faster but less portable,
13
+ # as it is native code. Check the documentation for RSolr::Message::Adapter
14
+ # for more information.
15
+ # Sunspot.config.solr.url::
16
+ # The URL at which to connect to Solr
17
+ # (default: 'http://localhost:8983/solr')
18
+ # Sunspot.config.pagination.default_per_page::
19
+ # Solr always paginates its results. This sets Sunspot's default result
20
+ # count per page if it is not explicitly specified in the query.
21
+ #
22
+ module Configuration
23
+ class <<self
24
+ # Factory method to build configuration instances.
25
+ #
26
+ # ==== Returns
27
+ #
28
+ # LightConfig::Configuration:: new configuration instance with defaults
29
+ #
30
+ def build #:nodoc:
31
+ LightConfig.build do
32
+ solr do
33
+ url 'http://127.0.0.1:8983/solr'
34
+ end
35
+ master_solr do
36
+ url nil
37
+ end
38
+ pagination do
39
+ default_per_page 30
40
+ end
41
+ end
42
+ end
43
+
44
+ # Location for the default solr configuration files,
45
+ # required for bootstrapping a new solr installation
46
+ #
47
+ # ==== Returns
48
+ #
49
+ # String:: Directory with default solr config files
50
+ #
51
+ def solr_default_configuration_location
52
+ File.join( File.dirname(__FILE__), '../../solr/solr/conf' )
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,50 @@
1
+ module Sunspot
2
+ #
3
+ # DataExtractors present an internal API for the indexer to use to extract
4
+ # field values from models for indexing. They must implement the #value_for
5
+ # method, which takes an object and returns the value extracted from it.
6
+ #
7
+ module DataExtractor #:nodoc: all
8
+ #
9
+ # AttributeExtractors extract data by simply calling a method on the block.
10
+ #
11
+ class AttributeExtractor
12
+ def initialize(attribute_name)
13
+ @attribute_name = attribute_name
14
+ end
15
+
16
+ def value_for(object)
17
+ object.send(@attribute_name)
18
+ end
19
+ end
20
+
21
+ #
22
+ # BlockExtractors extract data by evaluating a block in the context of the
23
+ # object instance, or if the block takes an argument, by passing the object
24
+ # as the argument to the block. Either way, the return value of the block is
25
+ # the value returned by the extractor.
26
+ #
27
+ class BlockExtractor
28
+ def initialize(&block)
29
+ @block = block
30
+ end
31
+
32
+ def value_for(object)
33
+ Util.instance_eval_or_call(object, &@block)
34
+ end
35
+ end
36
+
37
+ #
38
+ # Constant data extractors simply return the same value for every object.
39
+ #
40
+ class Constant
41
+ def initialize(value)
42
+ @value = value
43
+ end
44
+
45
+ def value_for(object)
46
+ @value
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,4 @@
1
+ %w(fields scope field_query query query_facet fulltext restriction
2
+ search).each do |file|
3
+ require File.join(File.dirname(__FILE__), 'dsl', file)
4
+ end
@@ -0,0 +1,150 @@
1
+ module Sunspot
2
+ module DSL
3
+ #
4
+ # Provides an API for areas of the query DSL that operate on specific
5
+ # fields. This functionality is provided by the query DSL and the dynamic
6
+ # query DSL.
7
+ #
8
+ class FieldQuery < Scope
9
+ def initialize(search, query, setup) #:nodoc:
10
+ @search, @query = search, query
11
+ super(query.scope, setup)
12
+ end
13
+
14
+ # Specify the order that results should be returned in. This method can
15
+ # be called multiple times; precedence will be in the order given.
16
+ #
17
+ # ==== Parameters
18
+ #
19
+ # field_name<Symbol>:: the field to use for ordering
20
+ # direction<Symbol>:: :asc or :desc (default :asc)
21
+ #
22
+ def order_by(field_name, direction = nil)
23
+ sort =
24
+ if special = Sunspot::Query::Sort.special(field_name)
25
+ special.new(direction)
26
+ else
27
+ Sunspot::Query::Sort::FieldSort.new(
28
+ @setup.field(field_name), direction
29
+ )
30
+ end
31
+ @query.add_sort(sort)
32
+ end
33
+
34
+ #
35
+ # DEPRECATED Use <code>order_by(:random)</code>
36
+ #
37
+ def order_by_random
38
+ order_by(:random)
39
+ end
40
+
41
+ # Request facets on the given field names. If the last argument is a hash,
42
+ # the given options will be applied to all specified fields. See
43
+ # Sunspot::Search#facet and Sunspot::Facet for information on what is
44
+ # returned.
45
+ #
46
+ # ==== Parameters
47
+ #
48
+ # field_names...<Symbol>:: fields for which to return field facets
49
+ #
50
+ # ==== Options
51
+ #
52
+ # :sort<Symbol>::
53
+ # Either :count (values matching the most terms first) or :index (lexical)
54
+ # :limit<Integer>::
55
+ # The maximum number of facet rows to return
56
+ # :minimum_count<Integer>::
57
+ # The minimum count a facet row must have to be returned
58
+ # :zeros<Boolean>::
59
+ # Return facet rows for which there are no matches (equivalent to
60
+ # :minimum_count => 0). Default is false.
61
+ # :extra<Symbol,Array>::
62
+ # One or more of :any and :none. :any returns a facet row with a count
63
+ # of all matching documents that have some value for this field. :none
64
+ # returns a facet row with a count of all matching documents that have
65
+ # no value for this field. The facet row(s) corresponding to the extras
66
+ # have a value of the symbol passed.
67
+ #
68
+ def facet(*field_names, &block)
69
+ options = Sunspot::Util.extract_options_from(field_names)
70
+
71
+ if block
72
+ if field_names.length != 1
73
+ raise(
74
+ ArgumentError,
75
+ "wrong number of arguments (#{field_names.length} for 1)"
76
+ )
77
+ end
78
+ search_facet = @search.add_query_facet(field_names.first, options)
79
+ Sunspot::Util.instance_eval_or_call(
80
+ QueryFacet.new(@query, @setup, search_facet),
81
+ &block
82
+ )
83
+ elsif options[:only]
84
+ field_names.each do |field_name|
85
+ field = @setup.field(field_name)
86
+ search_facet = @search.add_field_facet(field, options)
87
+ Util.Array(options[:only]).each do |value|
88
+ facet = Sunspot::Query::QueryFacet.new
89
+ facet.add_restriction(field, Sunspot::Query::Restriction::EqualTo, value)
90
+ @query.add_query_facet(facet)
91
+ search_facet.add_row(value, facet.to_boolean_phrase)
92
+ end
93
+ end
94
+ else
95
+ field_names.each do |field_name|
96
+ search_facet = nil
97
+ field = @setup.field(field_name)
98
+ facet =
99
+ if options[:time_range]
100
+ unless field.type == Sunspot::Type::TimeType
101
+ raise(
102
+ ArgumentError,
103
+ ':time_range can only be specified for Date or Time fields'
104
+ )
105
+ end
106
+ search_facet = @search.add_date_facet(field, options)
107
+ Sunspot::Query::DateFieldFacet.new(field, options)
108
+ else
109
+ search_facet = @search.add_field_facet(field)
110
+ Sunspot::Query::FieldFacet.new(field, options)
111
+ end
112
+ @query.add_field_facet(facet)
113
+ Util.Array(options[:extra]).each do |extra|
114
+ extra_facet = Sunspot::Query::QueryFacet.new
115
+ case extra
116
+ when :any
117
+ extra_facet.add_negated_restriction(
118
+ field,
119
+ Sunspot::Query::Restriction::EqualTo,
120
+ nil
121
+ )
122
+ when :none
123
+ extra_facet.add_restriction(
124
+ field,
125
+ Sunspot::Query::Restriction::EqualTo,
126
+ nil
127
+ )
128
+ else
129
+ raise(
130
+ ArgumentError,
131
+ "Allowed values for :extra are :any and :none"
132
+ )
133
+ end
134
+ search_facet.add_row(extra, extra_facet.to_boolean_phrase)
135
+ @query.add_query_facet(extra_facet)
136
+ end
137
+ end
138
+ end
139
+ end
140
+
141
+ def dynamic(base_name, &block)
142
+ dynamic_field_factory = @setup.dynamic_field_factory(base_name)
143
+ Sunspot::Util.instance_eval_or_call(
144
+ FieldQuery.new(@search, @query, dynamic_field_factory),
145
+ &block
146
+ )
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,100 @@
1
+ module Sunspot
2
+ module DSL #:nodoc:
3
+ # The Fields class provides a DSL for specifying field definitions in the
4
+ # Sunspot.setup block. As well as the #text method, which creates fulltext
5
+ # fields, uses #method_missing to allow definition of typed fields. The
6
+ # available methods are determined by the constants defined in
7
+ # Sunspot::Type - in theory (though this is untested), plugin developers
8
+ # should be able to add support for new types simply by creating new
9
+ # implementations in Sunspot::Type
10
+ #
11
+ class Fields
12
+ def initialize(setup) #:nodoc:
13
+ @setup = setup
14
+ end
15
+
16
+ # Add a text field. Text fields are tokenized before indexing and are
17
+ # the only fields searched in fulltext searches. If a block is passed,
18
+ # create a virtual field; otherwise create an attribute field.
19
+ #
20
+ # If options are passed, they will be applied to all the given fields.
21
+ #
22
+ # ==== Parameters
23
+ #
24
+ # names...<Symbol>:: One or more field names
25
+ #
26
+ # ==== Options
27
+ #
28
+ # :boost<Float>::
29
+ # Index-time boost that should be applied to this field for keyword search
30
+ # :default_boost<Float>::
31
+ # Default search-time boost to apply to this field during keyword
32
+ # search. Can be overriden with DSL::Fulltext#fields or
33
+ # DSL::Fulltext#boost_fields method.
34
+ #
35
+ def text(*names, &block)
36
+ options = names.pop if names.last.is_a?(Hash)
37
+ names.each do |name|
38
+ @setup.add_text_field_factory(
39
+ name,
40
+ options || {},
41
+ &block
42
+ )
43
+ end
44
+ end
45
+
46
+ #
47
+ # Specify a method or block that returns the geographical coordinates
48
+ # associated with the document. The object returned must respond to #first
49
+ # and #last (e.g., a two-element Array); or to #lat and one of #lng, #lon,
50
+ # or #long
51
+ #
52
+ def coordinates(name = nil, &block)
53
+ @setup.set_coordinates_field(name, &block)
54
+ end
55
+
56
+ #
57
+ # Specify a document-level boost. As with fields, you have the option of
58
+ # passing an attribute name which will be called on each model, or a block
59
+ # to be evaluated in the model's context. As well as these two options,
60
+ # this method can also take a constant number, meaning that all indexed
61
+ # documents of this class will have the specified boost.
62
+ #
63
+ # ==== Parameters
64
+ #
65
+ # attr_name<Symbol,~.to_f>:: Attribute name to call or a numeric constant
66
+ #
67
+ def boost(attr_name = nil, &block)
68
+ @setup.add_document_boost(attr_name, &block)
69
+ end
70
+
71
+ # method_missing is used to provide access to typed fields, because
72
+ # developers should be able to add new Sunspot::Type implementations
73
+ # dynamically and have them recognized inside the Fields DSL. Like #text,
74
+ # these methods will create a VirtualField if a block is passed, or an
75
+ # AttributeField if not.
76
+ #
77
+ # ==== Example
78
+ #
79
+ # Sunspot.setup(File) do
80
+ # time :mtime
81
+ # end
82
+ #
83
+ # The call to +time+ will create a field of type Sunspot::Types::TimeType
84
+ #
85
+ def method_missing(method, *args, &block)
86
+ begin
87
+ type = Type.const_get("#{Util.camel_case(method.to_s.sub(/^dynamic_/, ''))}Type")
88
+ rescue(NameError)
89
+ super(method.to_sym, *args, &block) and return
90
+ end
91
+ name = args.shift
92
+ if method.to_s =~ /^dynamic_/
93
+ @setup.add_dynamic_field_factory(name, type, *args, &block)
94
+ else
95
+ @setup.add_field_factory(name, type, *args, &block)
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,228 @@
1
+ module Sunspot
2
+ module DSL
3
+ #
4
+ # This DSL exposes the functionality provided by Solr's fulltext Dismax
5
+ # handler.
6
+ #
7
+ class Fulltext
8
+ attr_reader :exclude_fields #:nodoc:
9
+
10
+ def initialize(query, setup) #:nodoc:
11
+ @query, @setup = query, setup
12
+ @fields_added = false
13
+ @exclude_fields = []
14
+ end
15
+
16
+ #
17
+ # Specify which fields to search. Field names specified as arguments are
18
+ # given default boost; field boosts can be specified by passing a hash of
19
+ # field names keyed to boost values as the last argument.
20
+ #
21
+ # If you wish to boost certain fields without restricting which fields are
22
+ # searched, use #boost_fields
23
+ #
24
+ # === Example
25
+ #
26
+ # Sunspot.search(Post) do
27
+ # keywords 'search is cool' do
28
+ # fields(:body, :title => 2.0)
29
+ # end
30
+ # end
31
+ #
32
+ # This would search the :body field with default boost (1.0), and the :title
33
+ # field with a boost of 2.0
34
+ #
35
+ def fields(*field_names)
36
+ @fields_added = true
37
+ boosted_fields = field_names.pop if field_names.last.is_a?(Hash)
38
+ field_names.each do |field_name|
39
+ @setup.text_fields(field_name).each do |field|
40
+ @query.add_fulltext_field(field, field.default_boost)
41
+ end
42
+ end
43
+ if boosted_fields
44
+ boosted_fields.each_pair do |field_name, boost|
45
+ @setup.text_fields(field_name).each do |field|
46
+ @query.add_fulltext_field(field, boost)
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ #
53
+ # Exclude the given fields from the search. All fields that are configured
54
+ # for the types under search and not listed here will be searched.
55
+ #
56
+ def exclude_fields(*field_names)
57
+ @exclude_fields.concat(field_names)
58
+ end
59
+
60
+ #
61
+ # Enable keyword highlighting for this search. By default, the fields
62
+ # under search will be highlighted; you may also may pass one or more
63
+ # symbol arguments indicating fields to be highlighted (they don't even
64
+ # have to be the same fields you're searching).
65
+ #
66
+ # === Example
67
+ #
68
+ # Sunspot.search(Post) do
69
+ # keywords 'show me the highlighting' do
70
+ # highlight :title, :body
71
+ # end
72
+ # end
73
+ #
74
+ # You may also pass a hash of options as the last argument. Options are
75
+ # the following:
76
+ #
77
+ # Full disclosure: I barely understand what these options actually do;
78
+ # this documentation is pretty much just copied from the
79
+ # (http://wiki.apache.org/solr/HighlightingParameters#head-23ecd5061bc2c86a561f85dc1303979fe614b956)[Solr Wiki]
80
+ #
81
+ # :max_snippets::
82
+ # The maximum number of highlighted snippets to generate per field
83
+ # :fragment_size::
84
+ # The number of characters to consider for a highlighted fragment
85
+ # :merge_continuous_fragments::
86
+ # Collapse continuous fragments into a single fragment
87
+ # :phrase_highlighter::
88
+ # Highlight phrase terms only when they appear within the query phrase
89
+ # in the document
90
+ # :require_field_match::
91
+ # If true, a field will only be highlighted if the query matched in
92
+ # this particular field (only has an effect if :phrase_highlighter is
93
+ # true as well)
94
+ #
95
+ def highlight(*args)
96
+ options = args.last.kind_of?(Hash) ? args.pop : {}
97
+ fields = []
98
+ args.each { |field_name| fields.concat(@setup.text_fields(field_name)) }
99
+
100
+ @query.add_highlight(fields, options)
101
+ end
102
+
103
+ #
104
+ # Phrase fields are an awesome dismax feature that adds extra boost to
105
+ # documents for which all the fulltext keywords appear in close proximity
106
+ # in one of the given fields. Excellent for titles, headlines, etc.
107
+ #
108
+ # Boosted fields are specified in a hash of field names to a boost, as
109
+ # with the #fields and #boost_fields methods.
110
+ #
111
+ # === Example
112
+ #
113
+ # Sunspot.search(Post) do
114
+ # keywords 'nothing reveals like relevance' do
115
+ # phrase_fields :title => 2.0
116
+ # end
117
+ # end
118
+ #
119
+ def phrase_fields(boosted_fields)
120
+ if boosted_fields
121
+ boosted_fields.each_pair do |field_name, boost|
122
+ @setup.text_fields(field_name).each do |field|
123
+ @query.add_phrase_field(field, boost)
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ #
130
+ # The maximum number of words that can appear between search terms for a
131
+ # field to qualify for phrase field boost. See #query_phrase_slop for
132
+ # examples. Phrase slop is only meaningful if phrase fields are specified
133
+ # (see #phrase_fields), and it does not have an effect on which results
134
+ # are returned; only on what their respective boosts are.
135
+ #
136
+ def phrase_slop(slop)
137
+ @query.phrase_slop = slop
138
+ end
139
+
140
+ #
141
+ # Boost queries allow specification of an arbitrary scope for which
142
+ # matching documents should receive an extra boost. The block is evaluated
143
+ # in the usual scope DSL, and field names are attribute fields, not text
144
+ # fields, as in other scope.
145
+ #
146
+ # This method can be called more than once for different boost queries
147
+ # with different boosts.
148
+ #
149
+ # === Example
150
+ #
151
+ # Sunspot.search(Post) do
152
+ # keywords 'super fan' do
153
+ # boost(2.0) do
154
+ # with(:featured, true)
155
+ # end
156
+ # end
157
+ # end
158
+ #
159
+ # In the above search, featured posts will receive a boost of 2.0.
160
+ #
161
+ def boost(factor, &block)
162
+ Sunspot::Util.instance_eval_or_call(
163
+ Scope.new(@query.create_boost_query(factor), @setup),
164
+ &block
165
+ )
166
+ end
167
+
168
+ #
169
+ # Add boost to certain fields, without restricting which fields are
170
+ # searched.
171
+ #
172
+ # === Example
173
+ #
174
+ # Sunspot.search(Post) do
175
+ # keywords('pork sandwich') do
176
+ # boost_fields :title => 1.5
177
+ # end
178
+ # end
179
+ #
180
+ def boost_fields(boosts)
181
+ boosts.each_pair do |field_name, boost|
182
+ begin
183
+ @setup.text_fields(field_name).each do |field|
184
+ @query.add_fulltext_field(field, boost)
185
+ end
186
+ rescue Sunspot::UnrecognizedFieldError
187
+ # We'll let this one slide.
188
+ end
189
+ end
190
+ end
191
+
192
+ #
193
+ # The minimum number of search terms that a result must match. By
194
+ # default, all search terms must match; if the number of search terms
195
+ # is less than this number, the default behavior applies.
196
+ #
197
+ def minimum_match(minimum_match)
198
+ @query.minimum_match = minimum_match
199
+ end
200
+
201
+ #
202
+ # The number of words that can appear between the words in a
203
+ # user-entered phrase (i.e., keywords in quotes) and still match. For
204
+ # instance, in a search for "\"great pizza\"" with a query phrase slop of
205
+ # 1, "great pizza" and "great big pizza" will match, but "great monster of
206
+ # a pizza" will not. Default behavior is a query phrase slop of zero.
207
+ #
208
+ def query_phrase_slop(slop)
209
+ @query.query_phrase_slop = slop
210
+ end
211
+
212
+ #
213
+ # A tiebreaker coefficient for scores derived from subqueries that are
214
+ # lower-scoring than the maximum score subquery. Typically a near-zero
215
+ # value is useful. See
216
+ # http://wiki.apache.org/solr/DisMaxRequestHandler#tie_.28Tie_breaker.29
217
+ # for more information.
218
+ #
219
+ def tie(tie)
220
+ @query.tie = tie
221
+ end
222
+
223
+ def fields_added? #:nodoc:
224
+ @fields_added
225
+ end
226
+ end
227
+ end
228
+ end