You can use rules to enhance the user experience based on what they search for.
For example, if you’re building an app to search for airports, Algolia’s geolocation feature helpfully ranks results by proximity.
However, the nearest airport isn’t necessarily the best choice.
In Paris, a search based on proximity might rank Le Bourget, a small airport for private jets, over large airports like Charles de Gaulle or Orly.
As a solution, you could prioritize other factors over proximity .
For example, you could rank airports by their number of airline connections.
However, if you also set a geolocation parameter like aroundLatLngViaIP
, proximity remains the primary factor in determining the order of search results.
A better solution is to create a rule so that when users search for a specific city or country, it turns off the aroundLatLngViaIP
parameter for that query.
Before you begin
Before creating the rule, ensure that:
Create the rule in the dashboard
This example assumes you’re using the sample dataset .
Custom ranking and attributes for faceting
Go to the Algolia dashboard and select your Algolia application.
On the left sidebar, select Algolia Search
Search .
Select your Algolia index:
On the Configuration tab, click Ranking and Sorting .
Click Add custom ranking attribute and select the nb_airline_connections
attribute from the drop-down menu.
Click Facets , under Filtering and faceting , then click Add an Attribute and select country
and city
from the drop-down menu.
Save your changes.
Rule
Use the dashboard to create a rule that detects matches in facets city
and country
, and changes the search parameters accordingly.
Click Rules in the Algolia dashboard’s left sidebar menu.
Select Create your first rule or New rule .
In the drop-down menu, click Manual Editor .
In the Condition(s) section, keep Query toggled on, click Contains in the drop-down menu, and select country . {facet:country}
should appear in the input.
In the Consequence(s) section:
Click Add consequence and select Add Query Parameter .
In the input field that appears, add the JSON parameters to apply when a user query matches the rule:
{ "aroundLatLngViaIP": false }
Save your changes.
Click New Rule and then Manual Editor again.
In the Condition(s) section, keep Query toggled on, click Contains in the drop-down menu, and select city . {facet:city}
should appear in the input.
In the Consequence(s) section:
Click Add consequence and select Add Query Parameter .
In the input field that appears, add the JSON parameters to apply when a user query matches the rule:
{ "aroundLatLngViaIP": false }
Save your changes.
Create the rule with the API
Before creating the rule, set custom ranking and the attributes for faceting .
This example assumes you’re using the sample dataset .
Custom ranking and attributes for faceting
1
2
3
4
5
6
7
$index -> setSettings ([
'customRanking' => [
'desc(nb_airline_liaisons)'
],
'attributesForFaceting' => [
'city' , 'country'
]);
1
2
3
4
5
6
7
8
index . set_settings ({
customRanking: [
'desc(nb_airline_liaisons)'
],
attributesForFaceting: [
'city' , 'country'
]
})
1
2
3
4
5
6
7
8
index . setSettings ({
customRanking : [
' desc(nb_airline_liaisons) '
],
attributesForFaceting : [ ' city, country ' ]
}). then (() => {
// done
});
1
2
3
4
5
6
7
8
9
index . set_settings ({
'customRanking' : [
'desc(nb_airline_liaisons)'
],
'attributesForFaceting' : [
'city' ,
'country'
]
})
1
2
3
4
5
6
7
8
9
let settings = Settings ()
. set (\ . customRanking , to : [ . desc ( "nb_airline_liaisons" )])
. set (\ . attributesForFaceting , to : [ "city" , "country" ])
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
val settings = settings {
customRanking {
+ Desc ( "nb_airline_liaisons" )
}
attributesForFaceting {
+ "city"
+ "country"
}
}
index . setSettings ( settings )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
IndexSettings settings = new IndexSettings
{
AttributesForFaceting = new List < string >
{
"city" ,
"country"
},
CustomRanking = new List < string >
{
"desc(nb_airline_liaisons)"
}
};
index . SetSettings ( settings );
// Asynchronous
await index . SetSettingsAsync ( settings );
1
2
3
4
5
6
7
8
9
index . setSettings (
new IndexSettings ()
. setCustomRanking ( Collections . singletonList (
"desc(nb_airline_liaisons)"
))
. setAttributesForFaceting ( Arrays . asList (
"city" , "country"
))
);
1
2
3
4
res , err := index . SetSettings ( search . Settings {
CustomRanking : opt . CustomRanking ( "desc(nb_airline_liaisons)" ),
AttributesForFaceting : opt . AttributesForFaceting ( "city" , "country" ),
})
1
2
3
4
5
6
7
8
9
10
11
client . execute {
setSettings of "myIndex" `with` IndexSettings (
customRanking = Some ( Seq (
CustomRanking . desc ( "nb_airline_liaisons" )
)),
attributesForFaceting = Some ( Seq (
"city" ,
"country"
))
)
}
Create the rule
Use the batchRules
method to create a rule that detects matches in facets city
and country
, and changes the search parameters accordingly.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$index -> saveRules ([
[
'objectID' => 'country' ,
'conditions' => array ( array (
'pattern' => '{facet:country}' ,
'anchoring' => 'contains'
)),
'consequence' => [
'params' => [
'aroundLatLngViaIP' => false
]
]
],
[
'objectID' => 'city' ,
'conditions' => array ( array (
'pattern' => '{facet:city}' ,
'anchoring' => 'contains'
)),
'consequence' => [
'params' => [
'aroundLatLngViaIP' => false
]
]
]
]);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
index . batch_rules ([
{
objectID: 'country' ,
conditions: [{
pattern: '{facet:country}' ,
anchoring: 'contains'
}],
consequence: {
params: {
aroundLatLngViaIP: false
}
}
},
{
objectID: 'city' ,
conditions: [{
pattern: '{facet:city}' ,
anchoring: 'contains'
}],
consequence: {
params: {
aroundLatLngViaIP: false
}
}
}
])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
index . saveRules ([
{
objectID : ' country ' ,
conditions : [{
pattern : ' {facet:country} ' ,
anchoring : ' contains '
}],
consequence : {
params : {
aroundLatLngViaIP : false
}
}
},
{
objectID : ' city ' ,
conditions : [{
pattern : ' {facet:city} ' ,
anchoring : ' contains '
}],
consequence : {
params : {
aroundLatLngViaIP : false
}
}
}
]). then (() => {
// done
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
index . save_rules ([
{
'objectID' : 'country' ,
'conditions' : [{
'pattern' : '{facet:country}' ,
'anchoring' : 'contains'
}],
'consequence' : {
'params' : {
'aroundLatLngViaIP' : False
}
}
},
{
'objectID' : 'city' ,
'conditions' : [{
'pattern' : '{facet:city}' ,
'anchoring' : 'contains'
}],
'consequence' : {
'params' : {
'aroundLatLngViaIP' : False
}
}
}
])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
let rules : [ Rule ] = [
Rule ( objectID : "country" )
. set (\ . conditions , to : [
Rule . Condition ()
. set (\ . anchoring , to : . contains )
. set (\ . pattern , to : . facet ( "country" ))
])
. set (\ . consequence , to : Rule . Consequence ()
. set (\ . query , to : Query ()
. set (\ . aroundLatLngViaIP , to : false )
)
),
Rule ( objectID : "country" )
. set (\ . conditions , to : [
Rule . Condition ()
. set (\ . anchoring , to : . contains )
. set (\ . pattern , to : . facet ( "city" ))
])
. set (\ . consequence , to : Rule . Consequence ()
. set (\ . query , to : Query ()
. set (\ . aroundLatLngViaIP , to : false )
)
)
]
index . saveRules ( rules ) { 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
15
16
17
18
19
20
val country = Attribute ( "country" )
val city = Attribute ( "city" )
val rules = listOf (
Rule (
objectID = ObjectID ( "country" ),
conditions = listOf ( Condition ( Anchoring . Contains , Pattern . Facet ( country ))),
consequence = Consequence (
query = Query ( aroundLatLngViaIP = false )
)
),
Rule (
objectID = ObjectID ( "city" ),
conditions = listOf ( ondition ( Anchoring . Contains , Pattern . Facet ( city ))),
consequence = Consequence (
query = Query ( aroundLatLngViaIP = false )
)
)
)
index . saveRules ( rules )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
var rule1 = new Rule
{
ObjectID = "country" ,
Conditions = new List < Condition >
{
new Condition { Anchoring = "contains" , Pattern = "{facet:country}" }
},
Consequence = new Consequence
{
Params = new ConsequenceParams
{
AroundLatLngViaIP = false
}
}
};
var rule2 = new Rule
{
ObjectID = "city" ,
Conditions = new List < Condition >
{
new Condition { Anchoring = "contains" , Pattern = "{facet:city}" }
},
Consequence = new ConsequenceParams
{
Params = new ConsequenceParams
{
AroundLatLngViaIP = false
}
}
};
index . SaveRules ( new List < Rule > { rule1 , rule2 });
// Asynchronous
await index . SaveRulesAsync ( new List < Rule > { rule1 , rule2 });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ConsequenceParams params = new ConsequenceParams ();
params . setAroundLatLngViaIP ( false );
index . saveRules (
Arrays . asList (
new Rule ()
. setObjectID ( "country" )
. setConditions ( Collections . singletonList (
new Condition (). setPattern ( "{facet:country}" ). setAnchoring ( "contains" ))
)
. setConsequence ( new Consequence (). setParams ( params )),
new Rule ()
. setObjectID ( "city" )
. setCondition ( new Condition (). setPattern ( "{facet:city}" ). setAnchoring ( "contains" ))
. setConsequence ( new Consequence (). setParams ( params ))));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
rules := [] search . Rule {
{
ObjectID : "country" ,
Condition : [] search . RuleCondition {{ Anchoring : search . Contains , Pattern : "{facet:country}" }},
Consequence : search . RuleConsequence {
Params : & search . RuleParams {
QueryParams : search . QueryParams {
AroundLatLngViaIP : opt . AroundLatLngViaIP ( true ),
},
},
},
},
{
ObjectID : "city" ,
Conditions : [] search . RuleCondition {{ Anchoring : search . Contains , Pattern : "{facet:city}" }},
Consequence : search . RuleConsequence {
Params : & search . RuleParams {
QueryParams : search . QueryParams {
AroundLatLngViaIP : opt . AroundLatLngViaIP ( true ),
},
},
},
},
}
res , err := index . SaveRules ( rules )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
client . execute {
save rules Seq (
Rule (
objectID = "country" ,
conditions = Some ( Seq ( Condition (
pattern = "{facet:country}" ,
anchoring = "contains"
))),
consequence = Consequence (
params = Some ( Map ( "aroundLatLngViaIP" -> true ))
)
),
Rule (
objectID = "city" ,
conditions = Some ( Seq ( Condition (
pattern = "{facet:city}" ,
anchoring = "contains"
))),
consequence = Consequence (
params = Some ( Map ( "aroundLatLngViaIP" -> true ))
)
)
) inIndex "myIndex"
}
Query time
If a user query exactly matches a city or a country in your dataset, the rule sets aroundLatLngViaIP
to false
overriding any other parameters in the query.
For example, if a user searches for “Paris” or “China”, matching airports are ranked by nb_airline_liaisons
.
When not searching for either a city or a country, airports are ranked by distance from the user’s location.
1
2
3
$results = $index -> search ( 'query' , [
'aroundLatLngViaIP' => true
]);
1
2
3
results = index . search ( 'query' , {
aroundLatLngViaIP: true
})
1
2
3
4
5
index . search ( '' , {
aroundLatLngViaIP : true
}). then (({ hits }) => {
console . log ( hits );
});
1
2
3
results = index . search ( 'query' , {
'aroundLatLngViaIP' : True
})
1
2
3
4
5
6
7
8
9
let query = Query ()
. set (\ . query , to : "query" )
. set (\ . aroundLatLngViaIP , to : true )
index . search ( query : query ) { result in
if case . success ( let response ) = result {
print ( "Response: \( response ) " )
}
}
1
index . Search ( new Query ( "query" ) { AroundLatLngViaIP = false });
1
2
3
4
5
index . search (
new Query ( "query" )
. setAroundLatLngViaIP ( true ),
new RequestOptions ()
. addExtraHeader ( "X-Forwarded-For" , "94.228.178.246" ));
1
2
3
4
res , err := index . Search (
"query" ,
opt . AroundLatLngViaIP ( true ),
)
1
2
3
4
5
6
client . execute {
search into "myIndex" query Query (
query = Some ( "query" ),
aroundLatLngViaIP = Some ( true )
)
}
Example dataset
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
[
{
"name" : "Orly" ,
"city" : "Paris" ,
"country" : "France" ,
"_geoloc" : { "lat" : 48.725278 , "lng" : 2.359444 },
"nb_airline_connections" : 404
},
{
"name" : "Charles De Gaulle" ,
"city" : "Paris" ,
"country" : "France" ,
"_geoloc" : { "lat" : 49.012779 , "lng" : 2.55 },
"nb_airline_connections" : 1041
},
{
"name" : "Le Bourget" ,
"city" : "Paris" ,
"country" : "France" ,
"_geoloc" : { "lat" : 48.961487 , "lng" : 2.436966 },
"nb_airline_connections" : 0
},
{
"name" : "Ben Gurion" ,
"city" : "Tel-Aviv" ,
"country" : "Israel" ,
"_geoloc" : { "lat" : 32.011389 , "lng" : 34.886667 },
"nb_airline_connections" : 271
},
{
"name" : "Haifa" ,
"city" : "Haifa" ,
"country" : "Israel" ,
"_geoloc" : { "lat" : 32.809444 , "lng" : 35.043056 },
"nb_airline_connections" : 4
},
{
"name" : "Pudong" ,
"city" : "Shanghai" ,
"country" : "China" ,
"_geoloc" : { "lat" : 31.143378 , "lng" : 121.805214 },
"nb_airline_connections" : 825
},
{
"name" : "Hongqiao Intl" ,
"city" : "Shanghai" ,
"country" : "China" ,
"_geoloc" : { "lat" : 31.197875 , "lng" : 121.336319 },
"nb_airline_connections" : 411
}
]
Further reading
To learn how to import data into Algolia, see Send and update your data .