def _breakdown_prop_params(self, aggregate_operation: str, math_params: Dict): values_arr = get_breakdown_prop_values( self.filter, self.entity, aggregate_operation, self.team_id, extra_params=math_params, column_optimizer=self.column_optimizer, ) # :TRICKY: We only support string breakdown for event/person properties assert isinstance(self.filter.breakdown, str) if self.filter.breakdown_type == "person": breakdown_value, _ = get_property_string_expr( "person", self.filter.breakdown, "%(key)s", "person_props") elif self.filter.breakdown_type == "group": properties_field = f"group_properties_{self.filter.breakdown_group_type_index}" breakdown_value, _ = get_property_string_expr( "groups", self.filter.breakdown, "%(key)s", properties_field) else: breakdown_value, _ = get_property_string_expr( "events", self.filter.breakdown, "%(key)s", "properties") return ( { "values": values_arr }, BREAKDOWN_PROP_JOIN_SQL, { "breakdown_value_expr": breakdown_value }, breakdown_value, )
def _get_breakdown_conditions(self) -> str: if self._filter.breakdown: limit = self._filter.breakdown_limit_or_default first_entity = self._filter.entities[0] values = get_breakdown_prop_values(self._filter, first_entity, "count(*)", self._team.pk, limit, extra_params={"offset": 0}) # For people, pagination sets the offset param, which is common across filters # and gives us the wrong breakdown values here, so we override it. # For events, we assume breakdown values remain stable across the funnel, # so using just the first entity to get breakdown values is ok. self.params.update({"breakdown_values": values}) return ""
def _get_breakdown_conditions(self) -> Optional[str]: """ For people, pagination sets the offset param, which is common across filters and gives us the wrong breakdown values here, so we override it. For events, we assume breakdown values remain stable across the funnel, so using just the first entity to get breakdown values is ok. if this is a multi property breakdown then the breakdown values are misleading e.g. [Chrome, Safari], [95, 15] doesn't make clear that Chrome 15 isn't valid but Safari 15 is so the generated list here must be [[Chrome, 95], [Safari, 15]] """ if self._filter.breakdown: limit = self._filter.breakdown_limit_or_default first_entity = self._filter.entities[0] return get_breakdown_prop_values(self._filter, first_entity, "count(*)", self._team.pk, limit, extra_params={"offset": 0}) return None
def test_breakdown_person_props(self): p1 = Person.objects.create(team_id=self.team.pk, distinct_ids=["p1"], properties={"$browser": "test"}) _create_event( team=self.team, event="$pageview", distinct_id="p1", timestamp="2020-01-02T12:00:00Z", properties={"key": "val"}, ) self.team.test_account_filters = [ { "key": "email", "type": "person", "value": "posthog.com", "operator": "not_icontains" }, { "key": "$host", "type": "event", "value": [ "127.0.0.1:3000", "127.0.0.1:5000", "localhost:5000", "localhost:8000" ], "operator": "is_not", }, { "key": "distinct_id", "type": "event", "value": "posthog.com", "operator": "not_icontains" }, ] self.team.save() with freeze_time("2020-01-04T13:01:01Z"): filter = Filter( data={ "insight": "FUNNELS", "properties": [], "filter_test_accounts": True, "events": [{ "id": "$pageview", "name": "$pageview", "type": "events", "order": 0 }], "actions": [], "funnel_viz_type": "steps", "display": "FunnelViz", "interval": "day", "breakdown": "$browser", "breakdown_type": "person", "date_from": "-14d", "funnel_window_days": 14, }) res = get_breakdown_prop_values( filter, Entity({ "id": "$pageview", "type": "events" }), "count(*)", self.team.pk, 5) self.assertEqual(res, ["test"])
def test_breakdown_group_props(self): GroupTypeMapping.objects.create(team=self.team, group_type="organization", group_type_index=0) GroupTypeMapping.objects.create(team=self.team, group_type="company", group_type_index=1) create_group(team_id=self.team.pk, group_type_index=0, group_key="org:5", properties={"industry": "finance"}) create_group(team_id=self.team.pk, group_type_index=0, group_key="org:6", properties={"industry": "technology"}) create_group(team_id=self.team.pk, group_type_index=0, group_key="org:7", properties={"industry": "finance"}) create_group(team_id=self.team.pk, group_type_index=0, group_key="org:8", properties={ "industry": "another", "out": 1 }) create_group(team_id=self.team.pk, group_type_index=1, group_key="company:10", properties={"industry": "foobar"}) # :TRICKY: Test group type overlapping create_group(team_id=self.team.pk, group_type_index=1, group_key="org:8", properties={"industry": "foobar"}) for org_index in range(5, 9): _create_event( event="$pageview", distinct_id="person1", team=self.team, properties={"$group_0": f"org:{org_index}"}, timestamp="2020-01-02T12:00:00Z", ) filter = Filter( data={ "date_from": "2020-01-01T00:00:00Z", "date_to": "2020-01-12T00:00:00Z", "breakdown": "industry", "breakdown_type": "group", "breakdown_group_type_index": 0, "events": [{ "id": "$pageview", "type": "events", "order": 0, }], "properties": [{ "key": "out", "value": "", "type": "group", "group_type_index": 0, "operator": "is_not_set" }], }, team=self.team, ) result = get_breakdown_prop_values(filter, filter.entities[0], "count(*)", self.team.pk, 5) self.assertEqual(result, ["finance", "technology"])
def test_breakdown_person_props_with_entity_filter(self): p1 = Person.objects.create(team_id=self.team.pk, distinct_ids=["p1"], properties={"$browser": "test"}) _create_event( team=self.team, event="$pageview", distinct_id="p1", timestamp="2020-01-02T12:00:00Z", properties={"key": "val"}, ) p1 = Person.objects.create(team_id=self.team.pk, distinct_ids=["p2"], properties={"$browser": "test2"}) _create_event( team=self.team, event="$pageview", distinct_id="p2", timestamp="2020-01-02T12:00:00Z", properties={"key": "val"}, ) cohort = Cohort.objects.create(team=self.team, name="a", groups=[{ "properties": { "$browser": "test" } }]) cohort.calculate_people() cohort.calculate_people_ch() entity_params = [{ "id": "$pageview", "name": "$pageview", "type": "events", "order": 0, "properties": [{ "key": "id", "value": cohort.pk, "type": "cohort" }], }] with self.settings(USE_PRECALCULATED_CH_COHORT_PEOPLE=True): with freeze_time("2020-01-04T13:01:01Z"): filter = Filter( data={ "insight": "FUNNELS", "properties": [], "filter_test_accounts": False, "events": entity_params, "actions": [], "funnel_viz_type": "steps", "display": "FunnelViz", "interval": "day", "breakdown": "$browser", "breakdown_type": "person", "date_from": "-14d", "funnel_window_days": 14, }) res = get_breakdown_prop_values(filter, Entity(entity_params[0]), "count(*)", self.team.pk, 5) self.assertEqual(res, ["test"])
def test_breakdown_person_props_with_entity_filter_and_or_props_with_partial_pushdown( self): Person.objects.create(team_id=self.team.pk, distinct_ids=["p1"], properties={ "$browser": "test", "$os": "test" }) _create_event( team=self.team, event="$pageview", distinct_id="p1", timestamp="2020-01-02T12:00:00Z", properties={"key": "val"}, ) Person.objects.create(team_id=self.team.pk, distinct_ids=["p2"], properties={ "$browser": "test2", "$os": "test2" }) _create_event( team=self.team, event="$pageview", distinct_id="p2", timestamp="2020-01-02T12:00:00Z", properties={"key": "val2"}, ) Person.objects.create(team_id=self.team.pk, distinct_ids=["p3"], properties={ "$browser": "test3", "$os": "test3" }) _create_event( team=self.team, event="$pageview", distinct_id="p3", timestamp="2020-01-02T12:00:00Z", properties={"key": "val3"}, ) entity_params = [{ "id": "$pageview", "name": "$pageview", "type": "events", "order": 0, "properties": [{ "key": "$browser", "type": "person", "value": "test", "operator": "icontains" }], }] with self.settings(USE_PRECALCULATED_CH_COHORT_PEOPLE=True): with freeze_time("2020-01-04T13:01:01Z"): filter = Filter( data={ "insight": "FUNNELS", "properties": { "type": "OR", "values": [ { "key": "$os", "type": "person", "value": "test2", "operator": "exact" }, { "key": "key", "type": "event", "value": "val", "operator": "exact" }, ], }, "filter_test_accounts": False, "events": entity_params, "actions": [], "funnel_viz_type": "steps", "display": "FunnelViz", "interval": "day", "breakdown": "$browser", "breakdown_type": "person", "date_from": "-14d", "funnel_window_days": 14, }) res = sorted( get_breakdown_prop_values(filter, Entity(entity_params[0]), "count(*)", self.team.pk, 5)) self.assertEqual(res, ["test", "test2"])