Skip to content

Commit abe32d9

Browse files
authored
Merge pull request #1246 from vespa-engine/thomasht86/add-filters-in-grouping
Add filter support to Grouping DSL
2 parents 67e93ef + 63b9202 commit abe32d9

3 files changed

Lines changed: 558 additions & 3 deletions

File tree

tests/integration/test_integration_grouping.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,93 @@ def test_grouping_hits_per_group(self):
10671067
self.assertEqual(group_children[2]["value"], "Smith")
10681068
self.assertEqual(group_children[2]["relevance"], 6100)
10691069

1070+
def test_filter_multiple_groupings(self):
1071+
# Three piped grouping expressions with filters against the playground API
1072+
q = qb.test_filter_multiple_groupings()
1073+
print(f"Executing query: {q}")
1074+
api_resp = requests.get(
1075+
"https://api.search.vespa.ai/search/",
1076+
params={"yql": q},
1077+
)
1078+
result = api_resp.json()
1079+
children = result["root"]["children"]
1080+
self.assertEqual(len(children), 3)
1081+
1082+
# g1: group(1) filter(Brown AND Rocker arm) → 1 group, count=1, 1 hit
1083+
g1_groups = children[0]["children"][0]["children"]
1084+
self.assertEqual(len(g1_groups), 1)
1085+
self.assertEqual(g1_groups[0]["id"], "group:long:1")
1086+
self.assertEqual(g1_groups[0]["fields"]["count()"], 1)
1087+
# Verify the single hit is Brown's Rocker arm (price=2330)
1088+
g1_hits = g1_groups[0]["children"][0]["children"]
1089+
self.assertEqual(len(g1_hits), 1)
1090+
self.assertEqual(g1_hits[0]["fields"]["customer"], "Brown")
1091+
self.assertEqual(g1_hits[0]["fields"]["item"], "Rocker arm")
1092+
self.assertEqual(g1_hits[0]["fields"]["price"], 2330)
1093+
1094+
# g2: group(customer) filter(Rocker arm) → Brown=1, Smith=1
1095+
g2_groups = children[1]["children"][0]["children"]
1096+
self.assertEqual(len(g2_groups), 2)
1097+
self.assertEqual(g2_groups[0]["id"], "group:string:Brown")
1098+
self.assertEqual(g2_groups[0]["fields"]["count()"], 1)
1099+
self.assertEqual(g2_groups[1]["id"], "group:string:Smith")
1100+
self.assertEqual(g2_groups[1]["fields"]["count()"], 1)
1101+
1102+
# g3: group(item) filter(Brown) → 6 items, each count=1
1103+
g3_groups = children[2]["children"][0]["children"]
1104+
self.assertEqual(len(g3_groups), 6)
1105+
expected_items = [
1106+
"Exhaust valve",
1107+
"Head",
1108+
"Oil pan",
1109+
"Piston",
1110+
"Rocker arm",
1111+
"Spring",
1112+
]
1113+
for i, item_name in enumerate(expected_items):
1114+
self.assertEqual(g3_groups[i]["id"], f"group:string:{item_name}")
1115+
self.assertEqual(g3_groups[i]["fields"]["count()"], 1)
1116+
1117+
def test_filter_not_istrue(self):
1118+
# Filter for unpaid purchases, grouped by customer
1119+
q = qb.test_filter_not_istrue()
1120+
print(f"Executing query: {q}")
1121+
api_resp = requests.get(
1122+
"https://api.search.vespa.ai/search/",
1123+
params={"yql": q},
1124+
)
1125+
result = api_resp.json()
1126+
group_children = result["root"]["children"][0]["children"][0]["children"]
1127+
self.assertEqual(len(group_children), 3)
1128+
self.assertEqual(group_children[0]["id"], "group:string:Brown")
1129+
self.assertEqual(group_children[0]["fields"]["count()"], 6)
1130+
self.assertEqual(group_children[1]["id"], "group:string:Jones")
1131+
self.assertEqual(group_children[1]["fields"]["count()"], 7)
1132+
self.assertEqual(group_children[2]["id"], "group:string:Smith")
1133+
self.assertEqual(group_children[2]["fields"]["count()"], 7)
1134+
1135+
def test_filter_with_purchase_data(self):
1136+
# Query the playground API which has purchase data with attributes (map) and is_paid fields
1137+
q = qb.test_filter_with_purchase_data()
1138+
print(f"Executing query: {q}")
1139+
api_resp = requests.get(
1140+
"https://api.search.vespa.ai/search/",
1141+
params={"yql": q},
1142+
)
1143+
result = api_resp.json()
1144+
group_children = result["root"]["children"][0]["children"][0]["children"]
1145+
# Verify 3 groups: Brown, Jones, Smith
1146+
self.assertEqual(len(group_children), 3)
1147+
# Brown: sum(price) = 9137 (4 hits with sales_rep matching Bonn.* and price >= 1000)
1148+
self.assertEqual(group_children[0]["id"], "group:string:Brown")
1149+
self.assertEqual(group_children[0]["fields"]["sum(price)"], 9137)
1150+
# Jones: sum(price) = 2100 (1 hit)
1151+
self.assertEqual(group_children[1]["id"], "group:string:Jones")
1152+
self.assertEqual(group_children[1]["fields"]["sum(price)"], 2100)
1153+
# Smith: sum(price) = 11400 (5 hits)
1154+
self.assertEqual(group_children[2]["id"], "group:string:Smith")
1155+
self.assertEqual(group_children[2]["fields"]["sum(price)"], 11400)
1156+
10701157
def test_all(self):
10711158
"""This test runs all the test methods in the unit test class against a Docker Vespa instance that is fed with corresponding data.
10721159
We do not inspect and compare all the results. This is already done in vespa system test, and as long as we are sure that the generated

0 commit comments

Comments
 (0)