Skip to content

Add a instantMeiliSearch parameter to sort geopoints by proximity to the center of the map #554

@bidoubiwa

Description

@bidoubiwa

Current Behavior

When moving inside the Google Maps, search results are returned based on its position.
To determine what documents should be returned, instant-meilisearch calculates the middle point of the Maps window and the distance between each corner.
It then creates a filter (see geo filter documentation based on that middle point and the distance between each corner.

_geoRadius(lat, lng, distance_in_meters)

No sorting

The first itteration of instant-meilisearch's geosearch also provided by default a sort rule whereas geo points closer to the center of the map were considered more important than other.
Which created packs of markers in the center of the map:

Screenshot 2021-10-13 at 15 48 11

By removing them, the markers are more scattered, which make the maps look nicer:

Screenshot 2021-10-13 at 15 49 49

But what if we want to sort?

Without providing by default the sorting feature, we still want to provide the possibility to the user to sort its markers to be as close as possible to the center.

Solution

To enable sorting from the center point of the map, the solution is to provide a parameter proximityGeoRule in the instantMeiliSearch parameters. Which would default to false.

const searchClient = instantMeiliSearch(
  'https://demos.meilisearch.com',
  '...',
  {
    proximityGeoRule: true
  }
)

This will enable sorting.

Here are the steps to follow to implement this feature:

1. add a proximityGeoRule in the InstantMeiliSearch Parameter

// types.ts
type ClientParams = {
  primaryKey?: string
  placeholderSearch?: boolean
  sort?: string
  indexUid: string
  paginationTotalHits: number
  proximityGeoRule?: boolean
}

2. Add the information in the geoSearchContext

export type GeoSearchContext = {
  aroundLatLng?: string
  aroundLatLngViaIP?: boolean
  aroundRadius?: number | 'all'
  aroundPrecision?: number
  minimumAroundRadius?: number
  insideBoundingBox?: InsideBoundingBox
  insidePolygon?: ReadonlyArray<readonly number[]>
  proximityGeoRule?: boolean
}

3. Use the information in the geo-rule adapter

In geo-rules-adapter.ts if proximityGeoRule is set to true, sort filter should be added:

if (proximityGeoRule) {
  sort = `_geoPoint(${lat3}, ${lng3}):asc`
} else {
  sort = undefined
}

4. make aroundLatLng work without aroundRadius

Because aroundLatLng only provided a middle point, and not a radius, only a sort was previously done.

const sort = `_geoPoint(${lat3}, ${lng3}):asc`

Because of a lack of radius provided, we cannot create a filter is not possible.

Thus, if proximityGeoRule is set to true, the following condition should be added in geo-rules-adapter.ts

else if (middlePoint != null) {
    const [lat3, lng3] = middlePoint.split(',')
    const sort = `_geoPoint(${lat3}, ${lng3}):asc`
    return { sort }
  }

5. Add the sort in the search params adapter.

In the search params adapter filter from the geosearch adapter are added in the final search requests parameters sent to MeiliSearch.

if (geoRules?.filter) { ... }

The same should be added for sort:

  if (geoRules?.sort) {
    if (meiliSearchParams.sort) {
      meiliSearchParams.sort.unshift(geoRules.sort)
    } else {
      meiliSearchParams.sort = [geoRules.sort]
    }
  }

6. add tests

This behavior should be tested in geosearch.tests.ts

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions