Sometimes, specific terms can act as cues that you can use to filter search results. You can use positive, negative, or numerical filters:
- Positive filters include a specific subset of matching records in the results. For example, if a user types “diet” on a restaurant website, return every record that has “low-carb” or “low-fat”.
- Negative filters exclude matching records from results. For example, if a user types “gluten-free” on a restaurant website, you could filter out any gluten-containing meal.
- Numerical filters convert text queries into a numerical range. For example, if a user types “cheap” on a website for kitchen appliances, you could filter out anything costing more than $50.
Positive filters
If you want to filter out every non-diet-friendly meal whenever user’s search queries contain the term “diet”,
you could use the _tags
attribute to categorize meals depending on their individual qualities:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| [
{
"name": "Chicken Stuffed Baked Avocados",
"restaurant": "The Hive",
"_tags": ["low-carb"]
},
{
"name": "Spinach Quiche",
"restaurant": "Bert's Inn",
"_tags": ["low-carb", "vegetarian"]
},
{
"name": "Pizza Chicken Bake",
"restaurant": "Millbrook Deli",
"_tags": ["cheese"]
},
{
"name": "Strawberry Sorbet",
"restaurant": "The Hive",
"_tags": ["low-fat", "vegetarian", "vegan"]
}
]
|
When users include the term “diet” in their search, you want to automatically return every record that has “low-carb” or “low-fat” in their _tags
attribute. Because _tags
is already optimized for filtering, you don’t have to set it as an attribute for faceting. You can directly create a new Rule that detects the term “diet” in a query and applies a positive filter on tags “low-carb” and “low-fat”.
To use the term “diet” only for filtering and not as a search term,
add a consequence in your rule to remove the word from your query.
Using the API
To add a rule, use the saveRule
method.
When creating a rule, you must define a condition and a consequence.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| $rule = [
'objectID' => 'diet-rule',
'conditions' => array(array(
'pattern' => 'diet',
'anchoring' => 'contains',
)),
'consequence' => [
'params' => [
'filters' => '"low-carb" OR "low-fat"',
'query' => [
'edits' => [
[
'type' => 'remove',
'delete' => 'diet'
]
]
]
]
]
];
$response = $index->saveRule($rule);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| rule = {
objectID: 'diet-rule',
conditions: [{
pattern: 'diet',
anchoring: 'contains'
}],
consequence: {
params: {
filters: '"low-carb" OR "low-fat"',
query: {
edits: [
{
type: 'remove',
delete: 'diet'
}
]
}
}
}
}
index.save_rule(rule)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| const rule = {
objectID: 'diet-rule',
conditions: [{
pattern: 'diet',
anchoring: 'contains'
}],
consequence: {
params: {
filters: '"low-carb" OR "low-fat"',
query: {
edits: [
{
type: 'remove',
delete: 'diet'
}
]
}
}
}
};
index.saveRule(rule).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
| rule = {
'objectID': 'diet-rule',
'conditions': [
{
'pattern': 'diet',
'anchoring': 'contains'
},
],
'consequence': {
'params': {
'filters': '"low-carb" OR "low-fat"',
'query': {
'edits': [
{
'type': 'remove',
'delete': 'diet',
}
],
},
},
},
}
response = index.save_rule(rule)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| let rule = Rule(objectID: "diet-rule")
.set(\.conditions, to: [
Rule.Condition()
.set(\.anchoring, to: .contains)
.set(\.pattern, to: .literal("diet"))
])
.set(\.consequence, to: Rule.Consequence()
.set(\.queryTextAlteration, to: .edits([.remove("diet")]))
.set(\.query, to: Query().set(\.filters, to: "\"low-carb\" OR \"low-fat\""))
)
index.saveRule(rule) { 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
| val rules = rules {
rule(
"diet-rule",
listOf(Condition(Contains, Literal("diet"))),
Consequence(
edits = edits { +"diet" },
query = query {
filters {
orTag {
tag("low-carb")
tag("low-fat")
}
}
}
)
)
}
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
| var rule = new Rule
{
ObjectID = "diet-rule",
Conditions = new List<Condition>
{
new Condition { Anchoring = "contains", Pattern = "diet" }
},
Consequence = new Consequence
{
Params = new ConsequenceParams
{
Filters = "'low-carb' OR 'low-fat'",
Edits = new List<Edit>
{
new Edit {Type = EditType.Remove, Delete = "diet"}
}
}
}
};
index.SaveRule(rule);
// Asynchronous
await index.SaveRuleAsync(rule);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| Condition condition = new Condition()
.setPattern("diet")
.setAnchoring("contains");
ConsequenceQuery consequenceQuery =
new ConsequenceQuery().setEdits(Collections.singletonList(new Edit().setType("remove").setDelete("diet")));
ConsequenceParams params = new ConsequenceParams();
params.setConsequenceQuery(consequenceQuery);
params.setFilters("'low-carb' OR 'low-fat'");
Consequence consequence = new Consequence().setParams(params);
Rule rule = new Rule()
.setObjectID("diet-rule")
.setCondition(Collections.singletonList(condition))
.setConsequence(consequence);
index.saveRule(rule);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| rule := search.Rule{
ObjectID: "diet-rule",
Condition: []search.RuleCondition{{Anchoring: search.Contains, Pattern: "diet"}},
Consequence: search.RuleConsequence{
Params: &search.RuleParams{
Query: search.NewRuleQueryObject(
search.RuleQueryObjectQuery{
Edits: []search.QueryEdit{
search.RemoveEdit("diet"),
},
},
),
QueryParams: search.QueryParams{
Filters: opt.Filters("'low-carb' OR 'low-fat'"),
},
},
},
}
res, err := index.SaveRule(rule)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| val ruleToSave = Rule(
objectID = "diet-rule",
conditions = Some(Seq(Condition(
pattern = "diet",
anchoring = "contains"
))),
consequence = Consequence(
params = Seq(
Map("filters" -> "'low-carb' OR 'low-fat'"),
Map(
"query" -> Map(
"edits" -> Seq(
Edit("remove", "diet")
)
)
)
)
),
)
client.execute {
save rule ruleToSave inIndex "index_name"
}
|
Using the dashboard
You can also add rules from the Algolia dashboard.
- Select the Search product icon on your dashboard.
- Select the Rules section from the left sidebar menu in the Algolia dashboard.
- Under the heading Rules, select the index to which you’re adding a Rule.
- Select Create your first rule or New rule. In the drop-down menu, select Manual Editor.
- In the Condition(s) sections, keep Query contains and enter “diet” in the input field.
- In the Consequence(s) section:
- Click the Add consequence button and select Add Query Parameter.
- In the input field that appears, enter the JSON search parameter you want to add. For example:
{ "filters": "'low-carb' OR 'low-fat'" }
.
- Click the Add consequence button again and select Remove Word.
- Type or select “diet” in the input field.
- Save your changes.
Negative filters
To exclude gluten-containing foods from the search results,
when a user searches for gluten-free meals:
To do this:
- Create an
allergens
attribute (with “gluten” as one of the potential values).
- Create a rule that filters out records with “gluten” in that attribute.
Example records
1
2
3
4
5
6
7
8
9
10
11
12
| [
{
"name": "Pasta Bolognese",
"restaurant": "Millbrook Deli",
"allergens": ["eggs", "lactose"]
},
{
"name": "Breakfast Waffles",
"restaurant": "The Hive",
"allergens": ["gluten", "lactose"]
}
]
|
Using the API
Set allergens
as an attributesForFaceting
in your index:
1
2
3
4
5
| $index->setSettings([
'attributesForFaceting' => [
"allergens"
]
]);
|
1
2
3
4
5
| index.set_settings({
attributesForFaceting: [
'allergens'
]
})
|
1
2
3
4
5
6
7
| index.setSettings({
attributesForFaceting: [
'allergens'
]
}).then(() => {
// done
});
|
1
2
3
4
5
| index.set_settings({
'attributesForFaceting': [
'allergens',
],
})
|
1
2
3
4
5
6
7
8
| let settings = Settings()
.set(\.attributesForFaceting, to: ["allergens"])
index.setSettings(settings) { result in
if case .success(let response) = result {
print("Response: \(response)")
}
}
|
1
2
3
4
5
6
7
| val settings = settings {
attributesForFaceting {
+"allergens"
}
}
index.setSettings(settings)
|
1
2
3
4
5
6
7
8
9
10
11
12
| IndexSettings settings = new IndexSettings
{
AttributesForFaceting = new List<string>
{
"allergens"
}
};
index.SetSettings(settings);
// Asynchronous
await index.SetSettingsAsync(settings);
|
1
| index.setSettings(new IndexSettings().setAttributesForFaceting(Collections.singletonList("allergens")));
|
1
2
3
| res, err := index.SetSettings(search.Settings{
AttributesForFaceting: opt.AttributesForFaceting("allergens"),
})
|
1
2
3
4
5
6
7
| client.execute {
setSettings of "myIndex" `with` IndexSettings(
attributesForFaceting = Some(Seq(
"allergens"
))
)
}
|
- Use the
saveRule
method to create a rule that detects the term “gluten-free” in a query and applies a negative filter on facet value allergens:gluten
.
- Add a consequence in your rule to remove the word “gluten-free” from your query. This way, it won’t be used as a search term, only for filtering purposes.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| $rule = [
'objectID' => 'gluten-free-rule',
'conditions' => array(array(
'pattern' => 'gluten-free',
'anchoring' => 'contains',
))
'consequence' => [
'params' => [
'filters' => 'NOT allergens:gluten',
'query' => [
'edits' => [
[
'type' => 'remove',
'delete' => 'gluten-free'
]
]
]
]
]
];
$response = $index->saveRule($rule['objectID'], $rule);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| rule = {
objectID: 'gluten-free-rule',
conditions: [{
pattern: 'gluten-free',
anchoring: 'contains'
}],
consequence: {
params: {
filters: 'NOT allergens:gluten',
query: {
edits: [
{
type: 'remove',
delete: 'gluten-free'
}
]
}
}
}
}
index.save_rule(rule)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| const rule = {
objectID: 'gluten-free-rule',
conditions: [{
pattern: 'gluten-free',
anchoring: 'contains'
}],
consequence: {
params: {
filters: 'NOT allergens:gluten',
query: {
edits: [
{
type: 'remove',
delete: 'gluten-free'
}
]
}
}
}
};
index.saveRule(rule).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
| rule = {
'objectID': 'gluten-free-rule',
'conditions': [
{
'pattern': 'gluten-free',
'anchoring': 'contains',
},
],
'consequence': {
'params': {
'filters': 'NOT allergens:gluten',
'query': {
'edits': [
{
'type': 'remove',
'delete': 'gluten-free',
},
],
},
},
},
},
response = index.save_rule(rule)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| let rule = Rule(objectID: "gluten-free-rule")
.set(\.conditions, to: [
Rule.Condition()
.set(\.anchoring, to: .contains)
.set(\.pattern, to: .literal("gluten-free"))
])
.set(\.consequence, to: Rule.Consequence()
.set(\.queryTextAlteration, to: .edits([.remove("gluten-free")]))
.set(\.query, to: Query().set(\.filters, to: "NOT allergens:gluten"))
)
index.saveRule(rule) { 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 rules = rules {
rule(
"gluten-free-rule",
listOf(Condition(Contains, Literal("gluten-free"))),
Consequence(
edits = edits { +"gluten-free" },
query = query {
filters { and { facet("allergens", "gluten", isNegated = true) } }
}
)
)
}
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
| var rule = new Rule
{
ObjectID = "gluten-free-rule",
Conditions = new List<Condition>
{
new Condition { Anchoring = "contains", Pattern = "gluten-free" }
},
Consequence = new Consequence
{
Params = new ConsequenceParams
{
Filters = "NOT allergens:gluten",
Edits = new List<Edit>
{
new Edit {Type = EditType.Remove, Delete = "gluten-free"}
}
}
}
};
index.SaveRule(rule);
// Asynchronous
await index.SaveRuleAsync(rule);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| Condition condition = new Condition().setPattern("gluten-free").setAnchoring("contains");
ConsequenceQuery consequenceQuery =
new ConsequenceQuery().setEdits(Collections.singletonList(new Edit().setType("remove").setDelete("gluten-free")));
ConsequenceParams params = new ConsequenceParams();
params.setConsequenceQuery(consequenceQuery);
params.setFilters("NOT allergens:gluten");
Consequence consequence = new Consequence().setParams(params);
Rule rule =
new Rule()
.setObjectID("gluten-free-rule")
.setCondition(Collections.singletonList(condition))
.setConsequence(consequence);
index.saveRule(rule);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| rule := search.Rule{
ObjectID: "gluten-free-rule",
Conditions: []search.RuleCondition{{Anchoring: search.Contains, Pattern: "gluten-free"}},
Consequence: search.RuleConsequence{
Params: &search.RuleParams{
Query: search.NewRuleQueryObject(
search.RuleQueryObjectQuery{
Edits: []search.QueryEdit{
search.RemoveEdit("gluten-free"),
},
},
),
QueryParams: search.QueryParams{
Filters: opt.Filters("NOT allergens:gluten"),
},
},
},
}
res, err := index.SaveRule(rule)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| val ruleToSave = Rule(
objectID = "gluten-free-rule",
conditions = Some(Seq(Condition(
pattern = "gluten-free",
anchoring = "contains"
))),
consequence = Consequence(
params = Seq(
Map("filters" -> "NOT allergens:gluten"),
Map(
"query" -> Map(
"edits" -> Seq(
Edit("remove", "gluten-free")
)
)
)
)
),
)
client.execute {
save rule ruleToSave inIndex "index_name"
}
|
Using the dashboard
You can also add rules from the Algolia dashboard.
- Select the Search product icon on your dashboard and then select your index.
- Click the Configuration tab.
- In the Facets subsection of Filtering and Faceting, click the “Add an attribute” button and select the
allergens
attribute from the drop-down menu.
- Click the Rules tab.
- Select Create your first rule or New rule. In the drop-down menu, select Manual Editor.
- In the Condition(s) section, keep Query toggled on, select Contains in the drop-down menu, and enter “gluten-free” in the input field.
- In the Consequence(s) section:
- Click the Add consequence button and select Add Query Parameter.
- In the input field that appears, enter the JSON search parameter you want to add. For example:
{ "filters": "NOT allergens:gluten" }
- Click the Add consequence button again and select Remove Word.
- Type or select “gluten-free” in the input field.
- Save your changes.
Numerical filters
Consider the query “cheap toaster 800w”. You can use Rules to filter the results by “toaster” and “prices between 0 and 25” so that the only textual search is the remaining term, “800w”, which could further be used to limit the results with that wattage.
Rule
If query = “cheap toaster” then price < 10 and type=toaster
This requires two rules.
Using the API
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| // Turn JSON into an array
$rules = array(
array(
'objectID' => 'cheap',
'condition' => array(
'pattern' => 'cheap',
'anchoring' => 'contains'
),
'consequence' => array(
'params' => array(
'query' => array(
'remove' => 'cheap'
),
'filters' => 'price < 10'
)
)
)
);
// Push Rule to index
$index->batchRules($rules);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| rule = {
objectID: 'cheap',
condition: {
pattern: 'cheap',
anchoring: 'contains'
},
consequence: {
params: {
query: {
remove: 'cheap'
}
},
filters: 'price < 10'
}
}
index.save_rule(rule['objectID'], rule)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| index.saveRule({
objectID: 'cheap',
condition: {
pattern: 'cheap',
anchoring: 'contains',
},
consequence: {
params: {
query: {
remove: 'cheap',
},
},
filters: 'price < 10',
},
});
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| rule = {
'objectID': 'cheap',
'condition': {
'pattern': 'cheap',
'anchoring': 'contains'
},
'consequence': {
'params': {
'query': {
'remove': 'cheap'
}
}
},
'filters': 'price < 10'
}
response = index.save_rule(rule)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| let rule = Rule(objectID: "cheap")
.set(\.conditions, to: [
Rule.Condition()
.set(\.anchoring, to: .contains)
.set(\.pattern, to: .literal("cheap"))
])
.set(\.consequence, to: Rule.Consequence()
.set(\.queryTextAlteration, to: .edits([.remove("cheap")]))
.set(\.query, to: Query().set(\.filters, to: "price < 10"))
)
index.saveRule(rule) { 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
| val rules = rules {
rule(
"cheap",
conditions {
+condition(Contains, Literal("cheap"))
},
consequence(
edits = edits { +"cheap" },
query = query {
filters {
and { comparison("price", Less, 10) }
}
}
)
)
}
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
| var rule = new Rule
{
ObjectID = "cheap",
Conditions = new List<Condition> {
new Condition { Anchoring = "contains", Pattern = "cheap" }
},
Consequence = new Consequence
{
Params = new ConsequenceParams {
Filters = "price < 10",
Query = new ConsequenceQuery {
Edits = new List<Edit> {
new Edit {
Type = EditType.Remove,
Delete = "cheap"
}
}
}
}
}
};
index.SaveRule(rule);
// Asynchronous
await index.SaveRuleAsync(rule);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| Condition condition = new Condition()
.setPattern("cheap")
.setAnchoring("contains");
ConsequenceQuery consequenceQuery = new ConsequenceQuery()
.setEdits(Collections.singletonList(new Edit().setType("remove").setDelete("cheap")));
ConsequenceParams params = new ConsequenceParams()
.setConsequenceQuery(consequenceQuery).setFilters("price < 10");
Consequence consequence = new Consequence()
.setParams(params);
Rule rule = new Rule()
.setObjectID("cheap")
.setConditions(Collections.singletonList(condition))
.setConsequence(consequence);
// Synchronous
index.saveRule(rule);
// Asynchronous
index.saveRuleAsync(rule);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| rule := search.Rule{
ObjectID: "cheap",
Condition: search.RuleCondition{Anchoring: search.Contains, Pattern: "cheap"},
Consequence: search.RuleConsequence{
Params: &search.RuleParams{
Query: search.NewRuleQueryObject(
search.RuleQueryObjectQuery{
Edits: []search.QueryEdit{
search.RemoveEdit("cheap"),
},
},
),
QueryParams: search.QueryParams{
OptionalFilters: opt.Filter("price < 10"),
},
},
},
}
res, err := index.SaveRule(rule)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| val ruleToSave = Rule(
objectID = "cheap",
condition = Condition(
pattern = "cheap",
anchoring = "contains"
),
consequence = Consequence(
params = Seq(
Map("Filters" -> "price < 10"),
Map(
"query" -> Map(
"edits" -> Seq(
Edit("remove", "cheap")
)
)
)
)
),
)
client.execute {
save rule ruleToSave inIndex "index_name"
}
|
Using the dashboard
Since there are two rules, you must set up both separately.
Preparation
- Select the Search product icon on your dashboard and then select your index.
- Click the Configuration tab.
- In the Facets subsection of Filtering and Faceting, click the “Add an attribute” button and select the
product_type
attribute from the drop-down menu.
For the first rule
- Select the Rules section from the left sidebar menu in the Algolia dashboard.
- Under the heading Rules, select the index to which you’re adding a rule.
- Select Create your first rule or New rule. In the drop-down menu, click the Manual Editor option.
- In the Condition(s) section, keep Query toggled on, select Contains in the drop-down menu, and enter “toaster” in the input field.
- In the Consequence(s) section:
- Click the Add consequence button and select Add Query Parameter.
- In the input field that appears, add the JSON parameters you want to apply when the user’s query matches the Rule:
{ "filters": "product_type:toaster" }
- Click the Add consequence button again and select Remove Word.
- Type or select “toaster” in the input field.
- Save your changes.
For the second rule
- Go back to the Rules section.
- Select New rule. In the drop-down menu, click the Manual Editor option.
- In the Condition(s) section, keep Query toggled on, select Contains in the drop-down menu, and enter “cheap” in the input field.
- In the Consequence(s) section:
- Click the Add consequence button and select Add Query Parameter.
- In the input field that appears, add the JSON parameters you want to apply when the user’s query matches the Rule:
{ "filters": "price<10" }
- Click the Add consequence button again and select Remove Word.
- Type or select “cheap” in the input field.
- Save your changes.