laravel / scout

Laravel Scout provides a driver based solution to searching your Eloquent models.
https://laravel.com/docs/scout
MIT License
1.55k stars 329 forks source link

Geo Search Option? #12

Closed iolson closed 6 years ago

iolson commented 8 years ago

I was wondering if people would be interested in possibly a trait to say setup this entry to be able to be geo-searched on. As Algolia and Elasticsearch are separate in the way they do this, so it would require some setup in terms of how to get things setup for the array. If there is interest I can create a PR for this functionality.

the907 commented 8 years ago

Any movement on this?

I would be interested in helping!

iolson commented 8 years ago

I can start looking at getting things setup. Just got pulled away on a client project.

brino commented 8 years ago

For Elasticsearch the best way to do this would be to index a geo field and then add a function_score query to the should "clause" of a bool query. This increases the score based on distance from indexed doc's field val to the user's given origin.

To set up the query you need at minimum:

Could also allow more options for:

This would also mean that a special "location" field be indexed in advance for the query to run against.

That all being said, whats the general idea here? How would this geo search mechanism work in practice?

sandervanhooft commented 8 years ago

This would be great!

EdwardNelson commented 8 years ago

I had an attempt with #77. Going with what Taylor said what does everyone believe would be an elegant way to include additional functionality from Algolia and Elasticsearch and what are they key features that should be included?

I believe the following are important:

Maybe something like this:

Model::search('querystring')->withinLocation($lat, $lng, $radius)->get();

See #78

sandervanhooft commented 8 years ago

Before querying, the field mapping should be prepared to handle geopoints. This can only be done with a new/empty index as I understand it.

Is this possible using Scout, or do we need an external workaround for this?

I'll try to map geopoints directly using ES, before indexing documents with Scout, hopefully next week...

EdwardNelson commented 8 years ago

@sandervanhooft From this article it seems that sticking to convention means that a mapping does not need to be made. I believe that means it is then up to the developer to correctly set up their toSearchableArray() method on their model. However, I am not too familiar with ES. Let me know if my understanding is wrong

sandervanhooft commented 8 years ago

@edwardnelson Thanks for the article. It unfortunately mentions that since the update you do need to provide a mapping.

EdwardNelson commented 8 years ago

@sandervanhooft my fault for skimming the article and hoping for the best! You're completely right. Having to set the mappings on creation of the index and with updating the mappings once the index has been created having the potential to cause problems means that geosearch probably shouldn't be supported in scout? As not everyone will include lat/long from the outset. What's your opinion

sandervanhooft commented 8 years ago

@edwardnelson It depends on whether Scout breaks the geofield mapping after having set it manually. I plan to try that next week. Feel free to beat me to it :).

If that works than geosearch can IMHO be supported from Scout (and should be), with a sidenote on the mapping process.

For me personally, Scout is potentially incredible valuable for getting data easily into ElasticSearch. In my current setup I poll ElasticSearch through a isolated frontend, so the value of retrieval through Laravel Scout is not that high for me. This may change when more complex queries are supported. But because of the "abstraction layer" nature of Scout, I suspect it will never support all current ElasticSearch features.

Nevertheless, geospatial search is such a basic requirement I hope to see it fulfilled for and by the Laravel community. I don't feel fluent enough in Laravel to assist in this implementation, but am happy to help in any way I can. On Sat, 24 Sep 2016 at 11:51, EdwardNelson notifications@github.com wrote:

@sandervanhooft https://github.com/sandervanhooft my fault for skimming the article and hoping for the best! You're completely right. Having to set the mappings on creation of the index and with updating the mappings once the index has been created having the potential to cause problems means that geosearch probably shouldn't be supported in scout? As not everyone will include lat/long from the outset. What's your opinion

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/laravel/scout/issues/12#issuecomment-249356255, or mute the thread https://github.com/notifications/unsubscribe-auth/AG7dp7KlSEbHaaJmaAinxrwaPt5C2oosks5qtPKXgaJpZM4JkHTT .

sandervanhooft commented 8 years ago

@EdwardNelson I am happy to report that manually mapping works! :)

It takes 2 steps to get the geopoints into ElasticSearch:

  1. Manually prepare the elasticsearch type mapping for storing a geopoint field
  2. Prepare your Laravel model

1. Manually prepare the elasticsearch type mapping for storing a geopoint field Set up an explicit location type mapping in ElasticSearch prior to loading any data into it. You will not be able to change the mapping once there's data stored in the index (Or in ElasticSearch jargon: do this before documents are indexed for this type.) See example code below.

You only need to provide mapping for fields that are not automatically interpreted correctly by ElasticSearch. So in my case I only provided the location mapping.

I think the nicest way to do this manual mapping is actually to use a Laravel migration and the elasticsearch/elasticsearch package and the connection config used for Scout to set this up.

Anyone up for writing an example for this?

2. Prepare your Laravel model ElasticSearch accepts a location in these forms:

The Laravel Scout searchable trait is very easy to use if you have stored the location in a single table field, so it matches the Geo-point lat,lon string format or the geohash format . This way you don't need to do any customization and can stick to the formal Laravel Scout docs. If you have used two fields for lon and lat in your table than you'll need to provide a customized Model->toSearchableArray method to provide ElasticSearch with the correct format.

After this you can use Laravel Scout as you would normally use it.

Example mapping (source):

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "location": {
          "type": "geo_point"
        }
      }
    }
  }
}

With cURL this would be:

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "location": {
          "type": "geo_point"
        }
      }
    }
  }
}
EdwardNelson commented 8 years ago

@sandervanhooft Probably getting a bit out of my depth in terms of Elasticsearch. It looks good from my amateur eyes! Probably one for the docs if it can be condensed down? Any chance you can take a look at #78 to see if we can get it merged.

brino commented 8 years ago

From an elasticsearch point of view. Yes, I think this would do a fine job of filtering results outside of radius from origin!

EdwardNelson commented 8 years ago

Excellent, thanks!

xcaptain commented 7 years ago

I wrote an example in https://github.com/ErickTamayo/laravel-scout-elastic/issues/24

driesvints commented 6 years ago

You can use the example from here in order to achieve this: https://github.com/ErickTamayo/laravel-scout-elastic/issues/24#issuecomment-345137669