0
0
mirror of https://github.com/PostHog/posthog.git synced 2024-11-28 18:26:15 +01:00
posthog/ee/clickhouse/views/insights.py
Harry Waye 2550fb26c6
feat(funnel-people): return converted/dropped people url in funnel (#7057)
* test(funnel-people): add tests for converted/dropped people urls

As per https://github.com/PostHog/posthog/issues/6935 we are adding urls
to responses to attempt to improve consistency between insight responses
and the people we display in the UI.

This simply adds tests for these urls, just for funnel step response
shape. The other two types of response will be handled separately.

* feat(funnel-people): return converted/dropped people url in funnel

Here I have simply added converted / dropped urls in the base funnel.
This touches both clickhouse and postgres functionality, so I will
probably add in tests for postgres also, or just disable to postgres.

It doesn't pass yet as there is an issue in that the order appears to be
ignored by the people endpoint.

* fix(funnels): actually use strict/unordered persons querying

Previously we were always using the standard `ClickhouseFunnelPersons`
class for retrieving people from the `/api/persons/funnel/` endpoint.
This change selects from the unordered and strict variants based on the
`funnel_order_type` setting.

Refers to https://github.com/PostHog/posthog/issues/7058 although there
is a frontend component to add that will truely resolve the issue.

* feat(funnel-people): add people urls for funnels with breakdown

In this I have also removed any changes from the non-clickhouse code.
Note that there are two places I've added the url generation code, one
in the `ClickhouseFunnelBase` and another in the `ClickhouseFunnel`

I think the former covers the unordered and strict cases, and the later
for the breakdown case. I think there are further test that I'll need to
add to validate e.g. if breakdown + strict work as expected.

* Fix people urls for unordered funnels + breakdown

* test: add test for strict breakdown with people urls

* make funnel response assertions not check people url equality

* fix typing

* fix tests

* remove new line in postgres funnel.py

* clear cache on insight test start

* no really, clear the cache

* remove flakiness from strict funnel test

* correct the unordered test

* use absolute uris

* use step.index not step.order

* remove out of date comment

* use step.index, not step.order

* use step.index, remove unordered funnels comment

* use journeys_for instead of create_events
2021-11-12 14:50:39 +00:00

150 lines
5.9 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import json
from typing import Any, Dict, Type
from rest_framework.decorators import action
from rest_framework.request import Request
from rest_framework.response import Response
from ee.clickhouse.queries import ClickhousePaths
from ee.clickhouse.queries.clickhouse_retention import ClickhouseRetention
from ee.clickhouse.queries.clickhouse_stickiness import ClickhouseStickiness
from ee.clickhouse.queries.funnels import (
ClickhouseFunnel,
ClickhouseFunnelBase,
ClickhouseFunnelStrict,
ClickhouseFunnelTimeToConvert,
ClickhouseFunnelTrends,
ClickhouseFunnelUnordered,
)
from ee.clickhouse.queries.funnels.funnel_correlation import FunnelCorrelation
from ee.clickhouse.queries.sessions.clickhouse_sessions import ClickhouseSessions
from ee.clickhouse.queries.trends.clickhouse_trends import ClickhouseTrends
from ee.clickhouse.queries.util import get_earliest_timestamp
from posthog.api.insight import InsightViewSet
from posthog.constants import (
INSIGHT_FUNNELS,
INSIGHT_PATHS,
INSIGHT_SESSIONS,
INSIGHT_STICKINESS,
PATHS_INCLUDE_EVENT_TYPES,
TRENDS_STICKINESS,
FunnelOrderType,
FunnelVizType,
)
from posthog.decorators import cached_function
from posthog.models.filters import Filter
from posthog.models.filters.path_filter import PathFilter
from posthog.models.filters.retention_filter import RetentionFilter
from posthog.models.filters.sessions_filter import SessionsFilter
from posthog.models.filters.stickiness_filter import StickinessFilter
class ClickhouseInsightsViewSet(InsightViewSet):
@cached_function
def calculate_trends(self, request: Request) -> Dict[str, Any]:
team = self.team
filter = Filter(request=request, team=self.team)
if filter.insight == INSIGHT_STICKINESS or filter.shown_as == TRENDS_STICKINESS:
stickiness_filter = StickinessFilter(
request=request, team=team, get_earliest_timestamp=get_earliest_timestamp
)
result = ClickhouseStickiness().run(stickiness_filter, team)
else:
trends_query = ClickhouseTrends()
result = trends_query.run(filter, team)
self._refresh_dashboard(request=request)
return {"result": result}
@cached_function
def calculate_session(self, request: Request) -> Dict[str, Any]:
return {
"result": ClickhouseSessions().run(
team=self.team,
filter=SessionsFilter(request=request, data={"insight": INSIGHT_SESSIONS}, team=self.team),
)
}
@cached_function
def calculate_path(self, request: Request) -> Dict[str, Any]:
team = self.team
filter = PathFilter(request=request, data={"insight": INSIGHT_PATHS}, team=self.team)
funnel_filter = None
funnel_filter_data = request.GET.get("funnel_filter") or request.data.get("funnel_filter")
if funnel_filter_data:
if isinstance(funnel_filter_data, str):
funnel_filter_data = json.loads(funnel_filter_data)
funnel_filter = Filter(data={"insight": INSIGHT_FUNNELS, **funnel_filter_data}, team=self.team)
#  backwards compatibility
if filter.path_type:
filter = filter.with_data({PATHS_INCLUDE_EVENT_TYPES: [filter.path_type]})
resp = ClickhousePaths(filter=filter, team=team, funnel_filter=funnel_filter).run()
return {"result": resp}
@cached_function
def calculate_funnel(self, request: Request) -> Dict[str, Any]:
team = self.team
filter = Filter(request=request, data={"insight": INSIGHT_FUNNELS}, team=self.team)
funnel_order_class: Type[ClickhouseFunnelBase] = ClickhouseFunnel
if filter.funnel_order_type == FunnelOrderType.UNORDERED:
funnel_order_class = ClickhouseFunnelUnordered
elif filter.funnel_order_type == FunnelOrderType.STRICT:
funnel_order_class = ClickhouseFunnelStrict
if filter.funnel_viz_type == FunnelVizType.TRENDS:
return {
"result": ClickhouseFunnelTrends(team=team, filter=filter, funnel_order_class=funnel_order_class).run()
}
elif filter.funnel_viz_type == FunnelVizType.TIME_TO_CONVERT:
return {
"result": ClickhouseFunnelTimeToConvert(
team=team, filter=filter, funnel_order_class=funnel_order_class
).run()
}
else:
base_uri = request.build_absolute_uri("/")
return {"result": funnel_order_class(team=team, filter=filter, base_uri=base_uri).run()}
# ******************************************
# /projects/:id/insights/funnel/correlation
#
# params:
# - params are the same as for funnel
#
# Returns significant events, i.e. those that are correlated with a person
# making it through a funnel
# ******************************************
@action(methods=["GET", "POST"], url_path="funnel/correlation", detail=False)
def funnel_correlation(self, request: Request, *args: Any, **kwargs: Any) -> Response:
result = self.calculate_funnel_correlation(request)
return Response(result)
@cached_function
def calculate_funnel_correlation(self, request: Request) -> Dict[str, Any]:
team = self.team
filter = Filter(request=request)
base_uri = request.build_absolute_uri("/")
result = FunnelCorrelation(filter=filter, team=team, base_uri=base_uri).run()
return {"result": result}
@cached_function
def calculate_retention(self, request: Request) -> Dict[str, Any]:
team = self.team
data = {}
if not request.GET.get("date_from"):
data.update({"date_from": "-11d"})
filter = RetentionFilter(data=data, request=request, team=self.team)
result = ClickhouseRetention().run(filter, team)
return {"result": result}
class LegacyClickhouseInsightsViewSet(ClickhouseInsightsViewSet):
legacy_team_compatibility = True