Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ jobs:
- '3.1'
- '3.2'
- '3.3'
- '3.4'
- 'head'
gem: ['sunspot', 'sunspot_rails', 'sunspot_solr']
update-format: ['xml', 'json']
Expand Down
21 changes: 16 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,14 +498,21 @@ search.facet(:author_id).rows.each do |facet|
end
```

You can also filter facets using a regular expression. Requires Solr 7.7 or higher for `facet.matches` faceting support.
Facet values can be restricted to those matching a regular expression. Requires Solr 7.7 or
higher.

```ruby
# Posts that insensitive case match 'Lord' followed by 'Rings' anywhere in the post title
# Counts for post titles mentioning 'Lord' before 'Rings', in any case
search = Post.search do
facet :title, matches: '(?i)Lord.*Rings'
facet :title, matches: '(?i).*Lord.*Rings.*'
end
```

The pattern is a Java regular expression matched against the whole indexed value, so `Rings`
matches the value `Rings` and not the value `Lord of the Rings`. Wrap the pattern in `.*` to
match anywhere within a value. Only the facet the option is given to is restricted; other
facets in the same search return all of their values.

#### Query Facets

```ruby
Expand Down Expand Up @@ -1129,7 +1136,7 @@ node contains replicas of all shards in the cluster. If you have 4 shards on sep
nodes each of these nodes should have 4 replicas (one replica of each shard).

More information and usage examples could be found here:
https://lucene.apache.org/solr/guide/6_6/shards-and-indexing-data-in-solrcloud.html
https://lucene.apache.org/solr/guide/6_6/shards-and-indexing-data-in-solrcloud.html

### Highlighting

Expand Down Expand Up @@ -1513,16 +1520,20 @@ part of the `save` callbacks.
There are a number of ways to index manually within Ruby:
```ruby
# On a class itself
Person.reindex
Person.reindex # Reindexes every record in the scope
Sunspot.commit # or commit(true) for a soft commit (Solr4)
Person.solr_remove_all_from_index # Eliminates Person record from the index, including records that no longer exist

# On mixed objects
Sunspot.index [post1, item2]
Sunspot.index person3
Sunspot.commit # or commit(true) for a soft commit (Solr4)
Sunspot.remove_all!(User, Person)

# With autocommit
Sunspot.index! [post1, item2, person3]
Person.solr_remove_all_from_index!
Sunspot.remove_all!(User)
```

If you make a change to the object's "schema" (code in the `searchable` block),
Expand Down
3 changes: 3 additions & 0 deletions sunspot/lib/sunspot/query/abstract_field_facet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ def to_params
if @options[:prefix]
params[qualified_param('prefix')] = @options[:prefix].to_s
end
if @options[:matches]
params[qualified_param('matches')] = @options[:matches].to_s
end
params[qualified_param('mincount')] =
case
when @options[:minimum_count] then @options[:minimum_count].to_i
Expand Down
7 changes: 2 additions & 5 deletions sunspot/lib/sunspot/query/field_facet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ def initialize(field, options)
end

def to_params
super.tap do |params|
params[:"facet.field"] = [field_name_with_local_params]
params[:"facet.matches"] = @options[:matches] if @options[:matches]
end
super.merge(:"facet.field" => [field_name_with_local_params])
end

private
Expand All @@ -38,7 +35,7 @@ def field_name_with_local_params
end
"{!#{pairs.join(' ')}}#{@field.indexed_name}"
end
end
end
end
end
end
36 changes: 18 additions & 18 deletions sunspot/lib/sunspot/query/restriction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ class <<self
# available to the DSL.
#
# ==== Returns
#
#
# Array:: Collection of restriction class names
#
def names
constants - abstract_constants
end

#
#
# Convenience method to access a restriction class by an underscored
# symbol or string
#
Expand All @@ -35,7 +35,7 @@ def abstract_constants
end
end

#
#
# Subclasses of this class represent restrictions that can be applied to
# a Sunspot query. The Sunspot::DSL::Restriction class presents a builder
# API for instances of this class.
Expand All @@ -57,7 +57,7 @@ def initialize(negated, field, value)
@negated, @field, @value = negated, field, value
end

#
#
# A hash representing this restriction in solr-ruby's parameter format.
# All restriction implementations must respond to this method; however,
# the base implementation delegates to the #to_positive_boolean_phrase method, so
Expand All @@ -72,7 +72,7 @@ def to_params
{ :fq => [to_filter_query] }
end

#
#
# Return the boolean phrase associated with this restriction object.
# Differentiates between positive and negated boolean phrases depending
# on whether this restriction is negated.
Expand All @@ -88,7 +88,7 @@ def to_boolean_phrase
@field.local_params(value) : value
end

#
#
# Boolean phrase representing this restriction in the positive. Subclasses
# may choose to implement this method rather than #to_params; however,
# this method delegates to the abstract #to_solr_conditional method, which
Expand All @@ -105,7 +105,7 @@ def to_positive_boolean_phrase
"#{Util.escape(@field.indexed_name)}:#{to_solr_conditional}"
end

#
#
# Boolean phrase representing this restriction in the negated. Subclasses
# may choose to implement this method, but it is not necessary, as the
# base implementation delegates to #to_positive_boolean_phrase.
Expand All @@ -118,14 +118,14 @@ def to_negated_boolean_phrase
"-#{to_positive_boolean_phrase}"
end

#
#
# Whether this restriction should be negated from its original meaning
#
def negated? #:nodoc:
!!@negated
end

#
#
# Return a new restriction that is the negated version of this one. It
# is used by disjunction denormalization.
#
Expand Down Expand Up @@ -184,7 +184,7 @@ def to_solr_conditional
end
end

#
#
# Results must have field with value equal to given value. If the value
# is nil, results must have no value for the given field.
#
Expand Down Expand Up @@ -213,7 +213,7 @@ def to_solr_conditional
end
end

#
#
# Results must have field with value less than given value
#
class LessThan < Base
Expand All @@ -230,7 +230,7 @@ def to_solr_conditional
end
end

#
#
# Results must have field with value less or equal to than given value
#
class LessThanOrEqualTo < Base
Expand All @@ -247,7 +247,7 @@ def to_solr_conditional
end
end

#
#
# Results must have field with value greater than given value
#
class GreaterThan < Base
Expand All @@ -264,7 +264,7 @@ def to_solr_conditional
end
end

#
#
# Results must have field with value greater than or equal to given value
#
class GreaterThanOrEqualTo < Base
Expand All @@ -281,7 +281,7 @@ def to_solr_conditional
end
end

#
#
# Results must have field with value in given range
#
class Between < Base
Expand All @@ -302,7 +302,7 @@ def to_solr_conditional
end
end

#
#
# Results must have field with value included in given collection
#
class AnyOf < Base
Expand Down Expand Up @@ -343,7 +343,7 @@ def negated?
super
end
end

private

def to_solr_conditional
Expand All @@ -355,7 +355,7 @@ def to_solr_conditional
end
end

#
#
# Results must have a field with a value that begins with the argument.
# Most useful for strings, but in theory will work with anything.
#
Expand Down
17 changes: 17 additions & 0 deletions sunspot/spec/api/query/faceting_examples.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,23 @@
end
expect(connection).to have_last_search_with(:"f.title_ss.facet.prefix" => 'Test')
end

it 'sets the facet matches pattern' do
search do
facet :title, :matches => 'Test.*'
end
expect(connection).to have_last_search_with(:"f.title_ss.facet.matches" => 'Test.*')
end

it 'does not restrict other facets in the same search' do
search do
facet :title, :matches => 'Test.*'
facet :category_ids
end
expect(connection).to have_last_search_with(:"f.title_ss.facet.matches" => 'Test.*')
expect(connection).not_to have_last_search_with(:"f.category_ids_im.facet.matches")
expect(connection).not_to have_last_search_with(:"facet.matches")
end

it 'sends a query facet for :any extra' do
search do
Expand Down
18 changes: 9 additions & 9 deletions sunspot/spec/api/query/scope_examples.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
'expire_date_d:1983\-07\-08T00\:00\:00Z'
)
end

it 'scopes by exact match with boolean' do
search do
with :featured, false
Expand Down Expand Up @@ -63,13 +63,6 @@
expect(connection).to have_last_search_including(:fq, 'average_rating_ft:{3\.0 TO *}')
end

it 'scopes by between match with excluded end float range' do
search do
with(:average_rating).between 2.0...3.0
end
expect(connection).to have_last_search_including(:fq, 'average_rating_ft:[2\.0 TO 3\.0}')
end

it 'scopes by short-form between match with integers' do
search do
with :blog_id, 2..4
Expand All @@ -84,6 +77,13 @@
expect(connection).to have_last_search_including(:fq, 'average_rating_ft:[2\.0 TO 4\.0]')
end

it 'scopes by between match with excluded end float range' do
search do
with(:average_rating).between 2.0...3.0
end
expect(connection).to have_last_search_including(:fq, 'average_rating_ft:[2\.0 TO 3\.0}')
end

it 'scopes by any match with integer' do
search do
with(:category_ids).any_of [2, 7, 12]
Expand Down Expand Up @@ -132,7 +132,7 @@
end
expect(connection).to have_last_search_including(:fq, '-average_rating_ft:{3\.0 TO *}')
end

it 'scopes by not between match with shorthand' do
search do
without(:blog_id, 2..4)
Expand Down
8 changes: 0 additions & 8 deletions sunspot/spec/integration/faceting_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,6 @@ def self.test_field_type(name, attribute, field, *args)
expect(search.facet(:title).rows.map { |row| row.value }.sort).to eq(%w(three two))
end

it 'should limit facet values by regex match' do
search = Sunspot.search(Post) do
with :blog_id, 1
facet :title, :matches => 'o.+[aeiou]'
end
expect(search.facet(:title).rows.map { |row| row.value }.sort).to eq(%w(one four))
end

it 'should return :all facet' do
search = Sunspot.search(Post) do
with :blog_id, 1
Expand Down
3 changes: 1 addition & 2 deletions sunspot/spec/integration/field_grouping_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
group :title
end

expect(search.group(:title).groups).to include { |g| g.value == "Title1" }
expect(search.group(:title).groups).to include { |g| g.value == "Title2" }
expect(search.group(:title).groups.map(&:value)).to include("Title1", "Title2")
end

it "returns the number of matches unique groups" do
Expand Down
2 changes: 2 additions & 0 deletions sunspot/spec/integration/indexing_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@
end

it 'should correctly remove by model instance' do
Sunspot.remove_all!
post = Post.new(:title => 'test post')
Sunspot.index!(post)
Sunspot.remove!(post)
expect(Sunspot.search(Post) { with(:title, 'test post') }.results).to be_empty
end

it 'should correctly delete by ID' do
Sunspot.remove_all!
post = Post.new(:title => 'test post')
Sunspot.index!(post)
Sunspot.remove_by_id!(Post, post.id)
Expand Down
8 changes: 8 additions & 0 deletions sunspot/sunspot.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,17 @@ Gem::Specification.new do |s|
s.add_dependency 'rsolr', '>= 1.1.1', '< 3'
s.add_dependency 'pr_geohash', '~>1.0'
s.add_dependency 'bigdecimal'
s.add_dependency 'ostruct'
s.add_dependency 'logger'
s.add_development_dependency 'rake', '~> 13.2'
s.add_development_dependency 'rspec', '~> 3.7'
s.add_development_dependency 'appraisal', '~> 2.5'
s.add_development_dependency 'rdoc'

# Ruby 2.5 compatibility
if RUBY_VERSION < '2.6'
s.add_development_dependency 'psych', '< 4.0'
end

s.rdoc_options << '--webcvs=http://github.com/outoftime/sunspot/tree/master/%s' <<
'--title' << 'Sunspot - Solr-powered search for Ruby objects - API Documentation' <<
Expand Down
Loading
Loading