In this tutorial, you’ll learn how to filter results around a polygonal location. This location can either be set manually or taken from the current user position.
Dataset
The dataset contains 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' ,
'YourWriteAPIKey'
);
$index = $client -> initIndex ( 'your_index_name' );
1
2
3
4
require 'algolia'
client = Algolia :: Search :: Client . create ( 'YourApplicationID' , 'YourWriteAPIKey' )
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 ' , ' YourWriteAPIKey ' );
const index = client . initIndex ( ' your_index_name ' );
1
2
3
4
from algoliasearch.search_client import SearchClient
client = SearchClient . create ( 'YourApplicationID' , 'YourWriteAPIKey' )
index = client . init_index ( 'your_index_name' )
1
2
let client = SearchClient ( appID : "YourApplicationID" , apiKey : "YourWriteAPIKey" )
let index = client . index ( withName : "your_index_name" )
1
2
3
4
5
6
7
val client = ClientSearch (
applicationID = ApplicationID ( "YourApplicationID" ),
apiKey = APIKey ( "YourWriteAPIKey" )
)
val indexName = IndexName ( "your_index_name" )
client . initIndex ( indexName )
1
2
SearchClient client = new SearchClient ( "YourApplicationID" , "YourWriteAPIKey" );
SearchIndex index = client . InitIndex ( "your_index_name" );
1
2
3
4
SearchClient client =
DefaultSearchClient . create ( "YourApplicationID" , "YourWriteAPIKey" );
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" , "YourWriteAPIKey" )
index := client . InitIndex ( "your_index_name" )
}
1
2
// No initIndex
val client = new AlgoliaClient ( "YourApplicationID" , "YourWriteAPIKey" )
Even if we want to sort by distance to a location, we need the textual relevance to be good in case we refine the search with a query.
For that let’s 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
12
13
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
let settings = Settings ()
. set (\ . searchableAttributes , to : [
"name" ,
"city" ,
"country" ,
"iata_code"
])
. set (\ . customRanking , to : [ . desc ( "links_count" )])
index . setSettings ( settings ) { result in
if case . success ( let response ) = result {
print ( "Response: \( response ) " )
}
}
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 )
1
2
3
4
5
6
7
8
9
10
11
12
13
IndexSettings settings = new IndexSettings
{
SearchableAttributes = new List < string >
{
"name" ,
"city" ,
"country" ,
"iata_code" ,
}
CustomRanking = new List < string > { "desc(links_count)" }
};
index . SetSettings ( 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
client . execute {
setSettings 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" )))
)
}
Searchable attributes
We’re going to search in our 4 textual attributes: name
, city
, country
and iata_code
.
Custom Ranking
We will use the number of other connected airports to any airport as a ranking metric - the more connection the better.
Filtering inside a polygonal area
Let’s filter inside the United State of America.
USA can be considered as a polygon:
To filter inside this polygon we need the latitude and longitude of all the points:
42.01,-124.31,
48.835509470063045,-124.40453125000005
45.01082951668149,-65.95726562500005
31.247243545293433,-81.06578125000004
25.924152577235226,-97.68234374999997
32.300311895879545,-117.54828125
We are going to use the insidePolygon
parameter:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$polygon = [
42.01 ,
- 124.31 ,
48.835509470063045 ,
- 124.40453125000005 ,
45.01082951668149 ,
- 65.95726562500005 ,
31.247243545293433 ,
- 81.06578125000004 ,
25.924152577235226 ,
- 97.68234374999997 ,
32.300311895879545 ,
- 117.54828125
];
$results = $index -> search ( '' , [
'insidePolygon' => [ $polygon ]
]);
1
2
3
4
5
6
7
8
9
10
polygon = [
42.01 , - 124.31 ,
48.835509470063045 , - 124.40453125000005 ,
45.01082951668149 , - 65.95726562500005 ,
31.247243545293433 , - 81.06578125000004 ,
25.924152577235226 , - 97.68234374999997 ,
32.300311895879545 , - 117.54828125
]
results = index . search ( '' , { insidePolygon: [ polygon ] })
1
2
3
4
5
6
7
8
9
10
11
12
13
const polygon = [
42.01 , - 124.31 ,
48.835509470063045 , - 124.40453125000005 ,
45.01082951668149 , - 65.95726562500005 ,
31.247243545293433 , - 81.06578125000004 ,
25.924152577235226 , - 97.68234374999997 ,
32.300311895879545 , - 117.54828125
];
index . search ( ' query ' , {
insidePolygon : [ polygon ]
}). then (({ hits }) => {
console . log ( hits );
});
1
2
3
4
5
6
7
8
9
polygon = [
42.01 , - 124.31 ,
48.835509470063045 , - 124.40453125000005 ,
45.01082951668149 , - 65.95726562500005 ,
31.247243545293433 , - 81.06578125000004 ,
25.924152577235226 , - 97.68234374999997 ,
32.300311895879545 , - 117.54828125
]
results = index . search ( '' , { insidePolygon : [ polygon ] })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let polygon = Polygon (
( 42.01 , - 124.31 ),
( 48.835509470063045 , - 124.40453125000005 ),
( 45.01082951668149 , - 65.95726562500005 ),
( 31.247243545293433 , - 81.06578125000004 ),
( 25.924152577235226 , - 97.68234374999997 ),
( 32.300311895879545 , - 117.54828125 )
)
let query = Query ( "query" )
. set (\ . insidePolygon , to : [ polygon ])
index . search ( query : query ) { result in
if case . success ( let response ) = result {
print ( "Response: \( response ) " )
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
val query = query {
insidePolygon {
+ Polygon (
Point ( 42.01f , - 124.31f ),
Point ( 48.835509470063045f , - 124.40453125000005f ),
Point ( 45.01082951668149f , - 65.95726562500005f ),
Point ( 31.247243545293433f , - 81.06578125000004f ),
Point ( 25.924152577235226f , - 97.68234374999997f ),
Point ( 32.300311895879545f , - 117.54828125f )
)
}
}
index . search ( query )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
index . Search < T >( new Query ( "query" )
{
InsidePolygon = new List < List < float >>
{
new List < float >
{
42.01f ,
- 124.31f ,
48.835509470063045f ,
- 124.40453125000005f ,
45.01082951668149f ,
- 65.95726562500005f ,
31.247243545293433f ,
- 81.06578125000004f ,
25.924152577235226f ,
- 97.68234374999997f ,
32.300311895879545f ,
- 117.54828125f ,
}
}
});
1
2
3
4
5
6
7
8
9
index . search ( new Query (). setInsidePolygon (
Arrays . asList (
Arrays . asList ( 42.01f , - 124.31f ),
Arrays . asList ( 48.835509470063045f , - 124.40453125000005f ),
Arrays . asList ( 45.01082951668149f , - 65.95726562500005f ),
Arrays . asList ( 31.247243545293433f , - 81.06578125000004f ),
Arrays . asList ( 25.924152577235226f , - 97.68234374999997f ),
Arrays . asList ( 32.300311895879545f , - 117.54828125f )
)));
1
2
3
4
5
6
7
8
9
10
11
12
polygons := [][] float64 {
{
42.01 , - 124.31 ,
48.835509470063045 , - 124.40453125000005 ,
45.01082951668149 , - 65.95726562500005 ,
31.247243545293433 , - 81.06578125000004 ,
25.924152577235226 , - 97.68234374999997 ,
32.300311895879545 , - 117.54828125 ,
},
}
res , err := index . Search ( "" , opt . InsidePolygon ( polygons ))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
client . execute {
search into "myIndex" query Query (
query = Some ( "query" ),
insidePolygon = Some ( Seq (
InsidePolygon (
42.01f ,
- 124.31f ,
48.835509470063045f ,
- 124.40453125000005f ,
45.01082951668149f ,
- 65.95726562500005f
)
))
)
}
We are using the empty query (''
) because we want all airports.