I setup SearchKick and have it working nicely when each user has one location and the location data is stored in the User model. This part works fine. The next step was for me to move locations to their own model so that each user could list multiple locations. The problem is that I'm not sure how to index this. I've reviewed the documentation as well as several tutorials and I see how to do multiple models and that you need to map the field, but not sure how that works for SearchKick in the context of needing both latitude and longitude.
class User < ActiveRecord::Base
searchkick language: "dutch", callbacks: :async, merge_mappings: true,
mappings: {
user: {
properties: {
locations: {
type:"geo_point"
}
}
}
},
locations: ["location"]
scope :search_import, -> { includes(:locations) }
def search_data
attributes.merge(
location: [locations.map(&:latitude), locations.map(&:longitude)]
)
end
That is what I have in the User model. When I reindex it does pull from locations. If you look at the line that is third from last you'll see where I have two map functions and I don't think this is correct. I couldn't find anything in the SearchKick docs to indicate how to handle locations that are in a separate model. It doesn't seem like it would be all that uncommon.
Also, for clarity, here is the query that I'm using:
User.search '*', where: { location: { near: [52.3734, 4.89406], within: '2km' } }
Again, this works fine if I have the data within the User table. I'm actually not 100% certain that SearchKick actually supports multiple locations but it seems as though it does. Please advise if that is not the case.
Hey @blimey85, I've never tried to use multiple locations in the same field, so it's not intended to be supported. However, if it works as is, we should add a test case for it to make sure future updates don't break it.
It works when you have a User model that has longitude and latitude as fields in that model/table. In my case I need to be able to have a User that has multiple locations so I moved locations to their own model and did has many / belongs to associations. But now I'm not sure how to properly index them so that they are picked up when queried. I posted on Stack Overflow and Reddit but no advice on either one. I saw directions on how to handle multiple values by using map, but this is two values that need to get converted to geo_point. I'm very new to both SearchKick and Elasticsearch so still feeling my way along. I'll update if I'm able to figure anything out.
@blimey85 did you manage to do it? I'm facing the same situation :-/
Try this:
class User
has_many :locations
searchkick locations: ["locations"]
scope :search_import, -> { includes(:locations) }
def search_data
attributes.merge(
locations: locations.map { |loc| {lat: loc.latitude, lon: loc.longitude} }
)
end
end
Using:
class Event < ApplicationRecord
has_many :performances
scope :search_import, -> { includes(:performances) }
searchkick locations: ['locations'] #, callbacks: :async
def search_data
{
title: title,
description: description,
group_name: group.name,
locations: performances.map { |l| { lat: l.latitude, lon: l.longitude } }
}
end
end
and searching with:
Event.search '*', where: {
location: {
near: { lat: lat, lon: lon },
within: "#{params[:distance] || 30}mi"
}
},
order: {
_geo_distance: {
location: "#{lat},#{lon}",
order: 'asc',
unit: 'mi'
}
}
results in (User substituted with Event):
[400] {"error":{"root_cause":[{"type":"query_parsing_exception","reason":"failed to find geo_point field [location]","index":"events_development_20161024125441974","line":1,"col":147}],"type":"search_phase_execution_exception","reason":"all shards failed","phase":"query","grouped":true,"failed_shards":[{"shard":0,"index":"events_development_20161024125441974","node":"sDW2RccdQwmGmUkW0zW_5w","reason":{"type":"query_parsing_exception","reason":"failed to find geo_point field [location]","index":"events_development_20161024125441974","line":1,"col":147}}]},"status":400}
Actually locations (with an s) works:
locations: {
near: { lat: lat, lon: lon },
within: "#{params[:distance] || 30}mi"
}
@chrise86 so SearchKick supports multiple locations on a model?
It appears to yes
Awsome, thanks!
@chrise86 I have done the same thing as you, but I am getting the following error: Searchkick::InvalidQueryError: [400] {"error":{"root_cause":[{"type":"query_parsing_exception","reason":"failed to find geo_point field [location]","index":"pres_development","line":1,"col":120}],"type":"search_phase_execution_exception","reason":"all shards failed","phase":"query","grouped":true,"failed_shards":[{"shard":0,"index":"pres_development","node":"C1pDlIIVSEm2w-VvW5YRqQ","reason":{"type":"query_parsing_exception","reason":"failed to find geo_point field [location]","index":"pres_development","line":1,"col":120}}]},"status":400}
This is my config of searchkick in my model:
class Pre
searchkick locations: ["locations"]
def search_data
{
name: name,
hidden: hidden,
users_gender: users_gender,
median_age: median_age,
amount_of_participants: amount_of_participants,
locations: [{ lat: 37, lon: -114 }, {lat: 37, lon: -113}, {lat: 32, lon: -114}]
}
end
end
Any idea?
From the error, it looks like you're trying to query on a field named location instead of locations.
"reason":"failed to find geo_point field [location]"
Most helpful comment
Actually
locations(with ans) works: