Skip to content

Commit

Permalink
Filtering by geo arbitrary rectangle (#64)
Browse files Browse the repository at this point in the history
  • Loading branch information
syabruk authored Jan 17, 2024
1 parent 28f66cb commit 829daa5
Show file tree
Hide file tree
Showing 14 changed files with 131 additions and 35 deletions.
2 changes: 1 addition & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ AllCops:
TargetRubyVersion: '2.5'
DisabledByDefault: true
Layout/LineLength:
Max: 120
Max: 160
Style/Documentation:
Enabled: false
Style/FrozenStringLiteralComment:
Expand Down
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,35 @@ end
request.run(page: 1, page_size: 10)
```

### Filtering by a Geofilt

```ruby
spatial_point = Solr::SpatialPoint.new(lat: 40.0, lon: -120.0)

filters = [
Solr::Query::Request::Geofilt.new(field: :location, spatial_point: spatial_point, spatial_radius: 100)
]

request = Solr::Query::Request.new(search_term: 'term', filters: filters)
request.run(page: 1, page_size: 10)
```

### Filtering by an Arbitrary Rectangle

```ruby
spatial_rectangle = Solr::SpatialRectangle.new(
top_left: Solr::SpatialPoint.new(lat: 40.0, lon: -120.0),
bottom_right: Solr::SpatialPoint.new(lat: 30.0, lon: -110.0)
)

filters = [
Solr::Query::Request::Filter.new(type: :equal, field: :location, value: spatial_rectangle)
]

request = Solr::Query::Request.new(search_term: 'term', filters: filters)
request.run(page: 1, page_size: 10)
```

## Query with sorting

```ruby
Expand Down Expand Up @@ -374,7 +403,9 @@ Default sorting logic is following: nulls last, not-nulls first.
)
request.run(page: 1, page_size: 10)
```

### Dictionary boosting function

Sometimes you want to do a dictionary-style boosting
example: given a hash (dictionary)

Expand Down
2 changes: 2 additions & 0 deletions lib/solr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
require 'solr/document_collection'
require 'solr/grouped_document_collection'
require 'solr/response'
require 'solr/spatial_point'
require 'solr/spatial_rectangle'
require 'solr/request/http_request'
require 'solr/request/runner'
require 'solr/query/request'
Expand Down
2 changes: 1 addition & 1 deletion lib/solr/query/request.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require 'solr/query/request/facet'
require 'solr/query/request/filter'
require 'solr/query/request/boost_magnitude'
require 'solr/query/request/geo_filter'
require 'solr/query/request/geofilt'
require 'solr/query/request/sorting'
require 'solr/query/request/edismax_adapter'
require 'solr/query/request/grouping'
Expand Down
2 changes: 2 additions & 0 deletions lib/solr/query/request/filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ def solr_value
value.map { |v| to_primitive_solr_value(v) }.join(' OR ')
elsif value.is_a?(::Range)
to_interval_solr_value(value)
elsif value.is_a?(Solr::SpatialRectangle)
value.to_solr_s
else
to_primitive_solr_value(value)
end
Expand Down
26 changes: 0 additions & 26 deletions lib/solr/query/request/geo_filter.rb

This file was deleted.

28 changes: 28 additions & 0 deletions lib/solr/query/request/geofilt.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module Solr
module Query
class Request
class Geofilt
include Solr::Support::SchemaHelper

attr_reader :field, :spatial_point, :spatial_radius, :score

def initialize(field:, spatial_point:, spatial_radius:, score: nil)
raise ArgumentError, 'spatial_point must be a Solr::SpatialPoint' unless spatial_point.is_a?(Solr::SpatialPoint)

@field = field
@spatial_point = spatial_point
@spatial_radius = spatial_radius
@score = score
freeze
end

def to_solr_s
solr_field = solarize_field(@field)
filter = "{!geofilt sfield=#{solr_field} pt=#{spatial_point.to_solr_s} d=#{spatial_radius}"
filter << " score=#{score}" if score
filter + "}"
end
end
end
end
end
14 changes: 14 additions & 0 deletions lib/solr/spatial_point.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module Solr
class SpatialPoint
attr_reader :lat, :lon

def initialize(lat:, lon:)
@lat = lat
@lon = lon
end

def to_solr_s
"#{lat},#{lon}"
end
end
end
17 changes: 17 additions & 0 deletions lib/solr/spatial_rectangle.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Solr
class SpatialRectangle
attr_reader :top_right, :bottom_left

def initialize(top_right:, bottom_left:)
raise ArgumentError, 'top_right must be a Solr::SpatialPoint' unless top_right.is_a?(Solr::SpatialPoint)
raise ArgumentError, 'bottom_left must be a Solr::SpatialPoint' unless bottom_left.is_a?(Solr::SpatialPoint)

@top_right = top_right
@bottom_left = bottom_left
end

def to_solr_s
"[#{bottom_left.to_solr_s} TO #{top_right.to_solr_s}]"
end
end
end
9 changes: 9 additions & 0 deletions spec/query/request/filter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@
end
end

context 'when value is spatial rectangle' do
let(:top_right) { Solr::SpatialPoint.new(lat: 1.0, lon: 2.0) }
let(:bottom_left) { Solr::SpatialPoint.new(lat: 3.0, lon: 4.0) }
let(:spatial_rectangle) { Solr::SpatialRectangle.new(top_right: top_right, bottom_left: bottom_left) }

subject { described_class.new(type: :equal, field: :field, value: spatial_rectangle).to_solr_s }
it { is_expected.to eq('field:([3.0,4.0 TO 1.0,2.0])') }
end

context 'when value is date' do
subject { described_class.new(type: :equal, field: :field, value: Date.parse('2018-08-01')).to_solr_s }
it { is_expected.to eq('field:(2018-08-01T00:00:00Z)') }
Expand Down
7 changes: 0 additions & 7 deletions spec/query/request/geo_filter_spec.rb

This file was deleted.

9 changes: 9 additions & 0 deletions spec/query/request/geofilt_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
RSpec.describe Solr::Query::Request::Geofilt do
describe '.to_solr_s' do
let(:spatial_point) { Solr::SpatialPoint.new(lat: -25.429692, lon: -49.271265) }

subject { described_class.new(field: :machine_type, spatial_point: spatial_point, spatial_radius: 161) }

it { expect(subject.to_solr_s).to eq('{!geofilt sfield=machine_type pt=-25.429692,-49.271265 d=161}') }
end
end
7 changes: 7 additions & 0 deletions spec/spatial_point_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
RSpec.describe Solr::SpatialPoint do
describe '#to_solr_s' do
it 'returns a solr string' do
expect(described_class.new(lat: 1.0, lon: 2.0).to_solr_s).to eq('1.0,2.0')
end
end
end
10 changes: 10 additions & 0 deletions spec/spatial_rectangle_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
RSpec.describe Solr::SpatialRectangle do
describe '#to_solr_s' do
it 'returns a solr string' do
expect(described_class.new(
top_right: Solr::SpatialPoint.new(lat: 1.0, lon: 2.0),
bottom_left: Solr::SpatialPoint.new(lat: 3.0, lon: 4.0)
).to_solr_s).to eq('[3.0,4.0 TO 1.0,2.0]')
end
end
end

0 comments on commit 829daa5

Please sign in to comment.