In this tutorial, we’ll see how we can filter results around a location. This location can either be set manually or taken from the current user position.
Dataset
In this tutorial we’ll use a dataset of the 3000+ of the biggest airports in the world.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| [
{
"objectID": "3797",
"name": "John F Kennedy Intl",
"city": "New York",
"country": "United States",
"iata_code": "JFK",
"_geoloc": {
"lat": 40.639751,
"lng": -73.778925
},
"links_count": 911
}
]
|
To tell Algolia where each record is located, we need to have the latitude and longitude stored in the _geoloc
attribute.
You can download the dataset here. Have look at how to import it in Algolia here.
Initialize the client
1
2
3
4
5
6
7
8
9
10
11
12
| // composer autoload
require __DIR__ . '/vendor/autoload.php';
// if you are not using composer
// require_once 'path/to/algoliasearch.php';
$client = \Algolia\AlgoliaSearch\SearchClient::create(
'YourApplicationID',
'YourAdminAPIKey'
);
$index = $client->initIndex('your_index_name');
|
1
2
3
4
| require 'algolia'
client = Algolia::Search::Client.create('YourApplicationID', 'YourAdminAPIKey')
index = client.init_index('your_index_name')
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| // for the default version
const algoliasearch = require('algoliasearch');
// for the default version
import algoliasearch from 'algoliasearch';
// for the search only version
import algoliasearch from 'algoliasearch/lite';
// or just use algoliasearch if you are using a <script> tag
// if you are using AMD module loader, algoliasearch will not be defined in window,
// but in the AMD modules of the page
const client = algoliasearch('YourApplicationID', 'YourAdminAPIKey');
const index = client.initIndex('your_index_name');
|
1
2
3
4
| from algoliasearch.search_client import SearchClient
client = SearchClient.create('YourApplicationID', 'YourAdminAPIKey')
index = client.init_index('your_index_name')
|
1
2
| let client = SearchClient(appID: "YourApplicationID", apiKey: "YourAdminAPIKey")
let index = client.index(withName: "your_index_name")
|
1
2
| Client client = new Client("YourApplicationID", "YourAdminAPIKey");
Index index = client.getIndex("your_index_name");
|
1
2
| SearchClient client = new SearchClient("YourApplicationID", "YourAdminAPIKey");
SearchIndex index = client.InitIndex("your_index_name");
|
1
2
3
4
| SearchClient client =
DefaultSearchClient.create("YourApplicationID", "YourAdminAPIKey");
SearchIndex index = client.initIndex("your_index_name");
|
1
2
3
4
5
6
7
8
| package main
import "github.com/algolia/algoliasearch-client-go/v3/algolia/search"
func main() {
client := search.NewClient("YourApplicationID", "YourAdminAPIKey")
index := client.InitIndex("your_index_name")
}
|
1
2
| // No initIndex
val client = new AlgoliaClient("YourApplicationID", "YourAdminAPIKey")
|
1
2
3
4
5
6
7
| val client = ClientSearch(
applicationID = ApplicationID("latency"),
apiKey = APIKey("YourAdminAPIKey")
)
val indexName = IndexName("your_index_name")
client.initIndex(indexName)
|
Even if we want to sort by distance to a location we need the textual relevance to be good in case refine the search with a query.
For that lets configure the index.
1
2
3
4
5
6
7
8
9
10
11
| $index->setSettings([
'searchableAttributes' => [
'name',
'city',
'country',
'iata_code'
],
'customRanking' => [
'desc(links_count)'
]
]);
|
1
2
3
4
5
6
7
8
9
10
11
| index.set_settings(
searchableAttributes: [
'name',
'city',
'country',
'iata_code'
],
customRanking: [
'desc(links_count)'
]
)
|
1
2
3
4
5
6
7
8
9
10
11
| index.setSettings({
searchableAttributes: [
'name',
'city',
'country',
'iata_code'
],
customRanking: ['desc(links_count)'],
}).then(() => {
// done
});
|
1
2
3
4
5
6
7
8
9
10
11
| index.set_settings(
searchableAttributes: [
'name',
'city',
'country',
'iata_code'
],
customRanking: [
'desc(links_count)'
]
)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| let settings = [
"searchableAttributes": [
"name",
"city",
"country",
"iata_code"
],
"customRanking": [
"desc(links_count)"
]
]
index.setSettings(
settings,
completionHandler: { (content, error) -> Void in
// [...]
}
)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| index.setSettings(
new JSONObject()
.put(
"searchableAttributes",
new JSONArray()
.put("name")
.put("city")
.put("country")
.put("iata_code")
)
.put(
"customRanking",
new JSONArray()
.put("desc(links_count)")
)
);
|
1
2
3
4
5
6
7
8
9
10
| IndexSettings settings = new IndexSettings
{
SearchableAttributes = new List<string> { "name", "city", "country", "iata_code" },
CustomRanking = new List<string> { "desc(links_count)" }
};
index.SetSettings(setting);
// Asynchronous
await index.SetSettingsAsync(settings);
|
1
2
3
4
| index.setSettings(new IndexSettings()
.setSearchableAttributes(Arrays.asList("name", "city", "country", "iata_code"))
.setCustomRanking(Collections.singletonList("desc(links_count"))
);
|
1
2
3
4
5
6
7
8
9
| res, err := index.SetSettings(search.Settings{
SearchableAttributes: opt.SearchableAttributes(
"name",
"city",
"country",
"iata_code",
),
CustomRanking: opt.CustomRanking("desc(links_count)"),
})
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| val result: Future[Task] = client.execute {
changeSettings of "myIndex" `with` IndexSettings(
searchableAttributes = Some(Seq(
SearchableAttributes.attributes("name")
SearchableAttributes.attribute("city")
SearchableAttributes.unordered("country")
SearchableAttributes.attribute("iata_code")
))
customRanking = Some(Seq(
CustomRanking.desc("links_count")
))
)
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| val settings = settings {
searchableAttributes {
+"name"
+"city"
+"country"
+"iata_code"
}
customRanking {
+Desc("links_count")
}
}
index.setSettings(settings)
|
Searchable attributes
We’re going to search in our 4 textual attributes: name
, city
, country
and iata_code
.
Custom Ranking
Lets use the number of other connected airports to any airport as a ranking metric. The more connection the better.
Ranking
When filtering around a location, Algolia can also sort the results by distance from this location.
The sorting by distance happens in the criterion geo
of the ranking formula.
If you don’t have this criterion active, you cannot sort by distance.
Filtering around a given location
Let’s filter airports around New York City. New York City has a latitude of 40.71 and a longitude of -74.01.
We are going to use the aroundLatLng
parameter.
1
2
3
| $results = $index->search('', [
'aroundLatLng' => '40.71, -74.01'
]);
|
1
| results = index.search('', { aroundLatLng: '40.71, -74.01' })
|
1
2
3
4
5
| index.search('', {
aroundLatLng: '40.71, -74.01'
}).then(({ hits }) => {
console.log(hits);
});
|
1
2
3
| results = index.search('', {
'aroundLatLng': '40.71, -74.01'
})
|
1
2
3
4
5
6
| let query = Query(query: "")
query.aroundLatLng = LatLng(lat: 40.71, lng: -74.01)
index.search(query, completionHandler: { (res, error) in
print(res)
})
|
1
2
3
4
5
6
| index.search(
new Query("")
.setAroundLatLng(
new LatLng(40.71, -74.01)
)
);
|
1
2
3
4
| index.Search<T>(new Query("")
{
AroundLatLng = new List<string> { "40.71, -74.01" }
});
|
1
| index.search(new Query().setAroundLatLng("40.71, -74.01"));
|
1
| res, err := index.Search("", opt.AroundLatLng("40.71, -74.01"))
|
1
2
3
4
5
6
7
8
| client.execute {
search into "myIndex" query Query(
query = Some(""),
aroundLatLng = Some(
AroundLatLng("40.71, -74.01")
)
)
}
|
1
2
3
4
5
| val query = query {
aroundLatLng = Point(40.71f, -74.01f)
}
index.search(query)
|
We are using the empty query (''
) to tell that we want all airports
Filtering around the current user location
As we don’t know in advance the Lat/Lng coordinates of the current user, we can rely on the IP address that we’ll automatically associate to a location.
We are going to use the aroundLatLngViaIP
parameter.
1
2
3
4
5
6
7
8
9
10
11
| /**
* '94.228.178.246' should be replaced with the actual IP you would like to search around.
* Depending on your stack there are multiple ways to get this information.
*/
$ip = '94.228.178.246';
$results = $index->search('', [
'aroundLatLngViaIP' => true,
'X-Forwarded-For' => $ip
]);
|
1
2
3
4
5
6
7
8
| results = index.search('', {
aroundLatLngViaIP: true,
headers: {
# '94.228.178.246' should be replaced with the actual IP you would like to search around.
# Depending on your stack there are multiple ways to get this information.
'X-Forwarded-For': '94.228.178.246'
}
})
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| /**
* '94.228.178.246' should be replaced with the actual IP you would like to search around.
* Depending on your stack there are multiple ways to get this information.
*/
index.search('', {
aroundLatLngViaIP: true,
headers: {
'X-Forwarded-For': '94.228.178.246'
}
}).then(({ hits }) => {
console.log(hits);
});
|
1
2
3
4
5
6
7
8
9
| # '94.228.178.246' should be replaced with the actual IP you would like to search around.
# Depending on your stack there are multiple ways to get this information.
ip = '94.228.178.246'
results = index.search('', {
'aroundLatLngViaIP': True,
'X-Forwarded-For': ip
})
|
1
2
3
4
5
6
7
8
9
10
11
| /// '94.228.178.246' should be replaced with the actual IP you would like to search around.
/// Depending on your stack there are multiple ways to get this information.
client.setHeader(withName: "X-Forwarded-For", to: "94.228.178.246")
let query = Query()
query.aroundLatLngViaIP = true
index.search(query, completionHandler: { (res, error) in
print(res)
})
|
1
2
3
4
5
6
7
8
| // '94.228.178.246' should be replaced with the actual IP you would like to search around.
// Depending on your stack there are multiple ways to get this information.
client.setHeader("X-Forwarded-For", "94.228.178.246")
index.search(
new Query().setAroundLatLngViaIP(true)
);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // '94.228.178.246' should be replaced with the actual IP you would like to search around.
// Depending on your stack there are multiple ways to get this information.
var configuration = new SearchConfig("YourApplicationID", "YourAdminAPIKey")
{
DefaultHeaders = new Dictionary<string, string> { { "X-Forwarded-For", "94.228.178.246" } }
};
SearchClient client = new SearchClient(configuration);
index.Search<T>(new Query("")
{
AroundLatLngViaIP = true
});
|
1
2
3
4
5
6
7
8
9
| // '94.228.178.246' should be replaced with the actual IP you would like to search around.
// Depending on your stack there are multiple ways to get this information.
index.search(
new Query()
.setAroundLatLngViaIP(true),
new RequestOptions()
.addExtraHeader("X-Forwarded-For", "94.228.178.246")
);
|
1
2
3
4
5
6
7
8
| // "94.228.178.246" should be replaced with the actual IP you would like to search around.
// Depending on your stack there are multiple ways to get this information.
extraHeaders := opt.ExtraHeaders(map[string]string{
"X-Forwarded-For": "94.228.178.246",
})
res, err := index.Search("", opt.AroundLatLngViaIP(true), extraHeaders)
|
1
2
3
4
5
6
7
8
9
10
11
| // '94.228.178.246' should be replaced with the actual IP you would like to search around.
// Depending on your stack there are multiple ways to get this information.
client.execute {
search into "myIndex" query Query(
query = Some(""),
aroundLatLngViaIP = Some(true)
) options RequestsOptions(
extraHeaders = Some(Map("X-Forwarded-For" -> "94.228.178.246"))
)
}
|
1
2
3
4
5
6
7
8
9
10
| /**
* '94.228.178.246' should be replaced with the actual IP you would like to search around.
* Depending on your stack there are multiple ways to get this information.
*/
val query = query {
aroundLatLngViaIP = true
}
index.search(query, requestOptions { headerForwardedFor("94.228.178.246") })
|
Filtering Radius
By default the engine will define automatically a radius to filter on depending on the area density.
To define the radius ourselves we can use the aroundRadius
parameter. The bigger it is the less filtering you have.
Let’s sort by distance to New York City, taking a radius of 1000 km.
1
2
3
4
| $results = $index->search('', [
'aroundLatLng' => '40.71, -74.01'
'aroundRadius' => 1000000 // 10000 km
]);
|
1
2
3
4
| results = index.search('', {
aroundLatLng: '40.71, -74.01',
aroundRadius: 1000000 # 1000 km
})
|
1
2
3
4
5
6
| index.search('', {
aroundLatLng: '40.71, -74.01',
aroundRadius: 1000000 // 1000 km
}).then(({ hits }) => {
console.log(hits);
});
|
1
2
3
4
| results = index.search('', {
'aroundLatLng': '40.71, -74.01'
'aroundRadius' => 1000000 // 1000 km
})
|
1
2
3
4
5
6
7
| let query = Query(query: "")
query.aroundLatLng = LatLng(lat: 40.71, lng: -74.01)
query.aroundRadius = .explicit(1000000) // 1000 km
index.search(query, completionHandler: { (res, error) in
print(res)
})
|
1
2
3
4
5
6
7
| index.search(
new Query("")
.setAroundLatLng(
new LatLng(40.71, -74.01)
)
.setAroundRadius(1000000) // 1000 km
);
|
1
2
3
4
5
| index.Search<T>(new Query("")
{
AroundLatLng = new List<string> { "40.71, -74.01" },
AroundRadius = 1000000 // 1000 km
});
|
1
2
3
4
| index.search(new Query()
.setAroundLatLng("40.71, -74.01")
.setAroundRadius(AroundRadius.of(1000000)) // 1000 km
);
|
1
2
3
4
5
| res, err := index.Search(
"",
opt.AroundLatLng("40.71, -74.01"),
opt.AroundRadius(1000000), // 1000 km
)
|
1
2
3
4
5
6
7
8
9
10
11
| client.execute {
search into "myIndex" query Query(
query = Some(""),
aroundLatLng = Some(
AroundLatLng("40.71, -74.01")
),
aroundRadius = Some(
AroundRadius.integer(1000000)
) // 1000 km
)
}
|
1
2
3
4
5
6
| val query = query {
aroundLatLng = Point(40.71f, -74.01f)
aroundRadius = AroundRadius.InMeters(1000000) // 10000 km
}
index.search(query)
|