Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
jurajmajerik committed Oct 30, 2024
1 parent 14b732f commit 1a65ec9
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 26 deletions.
8 changes: 4 additions & 4 deletions frontend/src/queries/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -5236,6 +5236,9 @@
"experiment_id": {
"type": "integer"
},
"funnels_query": {
"$ref": "#/definitions/FunnelsQuery"
},
"kind": {
"const": "ExperimentFunnelsQuery",
"type": "string"
Expand All @@ -5246,12 +5249,9 @@
},
"response": {
"$ref": "#/definitions/ExperimentFunnelsQueryResponse"
},
"source": {
"$ref": "#/definitions/FunnelsQuery"
}
},
"required": ["experiment_id", "kind", "source"],
"required": ["experiment_id", "funnels_query", "kind"],
"type": "object"
},
"ExperimentFunnelsQueryResponse": {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/queries/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1651,7 +1651,7 @@ export type CachedExperimentFunnelsQueryResponse = CachedQueryResponse<Experimen

export interface ExperimentFunnelsQuery extends DataNode<ExperimentFunnelsQueryResponse> {
kind: NodeKind.ExperimentFunnelsQuery
source: FunnelsQuery
funnels_query: FunnelsQuery
experiment_id: integer
}

Expand Down
45 changes: 36 additions & 9 deletions frontend/src/scenes/experiments/experimentLogic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -827,14 +827,23 @@ export const experimentLogic = kea<experimentLogicType>([
},
],
secondaryMetricResults: [
null as SecondaryMetricResults[] | null,
null as
| SecondaryMetricResults[]
| (CachedExperimentTrendsQueryResponse | CachedExperimentFunnelsQueryResponse)[]
| null,
{
loadSecondaryMetricResults: async (refresh?: boolean) => {
loadSecondaryMetricResults: async (
refresh?: boolean
): Promise<
| SecondaryMetricResults[]
| (CachedExperimentTrendsQueryResponse | CachedExperimentFunnelsQueryResponse)[]
| null
> => {
if (values.featureFlags[FEATURE_FLAGS.EXPERIMENTS_HOGQL]) {
const secondaryMetrics =
values.experiment?.metrics?.filter((metric) => metric.type === 'secondary') || []

return await Promise.all(
return (await Promise.all(
secondaryMetrics.map(async (metric) => {
try {
const response: ExperimentResults = await api.create(
Expand All @@ -851,7 +860,7 @@ export const experimentLogic = kea<experimentLogicType>([
return {}
}
})
)
)) as unknown as (CachedExperimentTrendsQueryResponse | CachedExperimentFunnelsQueryResponse)[]
}

const refreshParam = refresh ? '&refresh=true' : ''
Expand All @@ -870,6 +879,7 @@ export const experimentLogic = kea<experimentLogicType>([
last_refresh: secResults.last_refresh,
}
}

return {
...secResults.result,
fakeInsightId: Math.random().toString(36).substring(2, 15),
Expand Down Expand Up @@ -1279,9 +1289,10 @@ export const experimentLogic = kea<experimentLogicType>([
| CachedExperimentTrendsQueryResponse
| CachedExperimentFunnelsQueryResponse
| null,
variant: string
variant: string,
type: 'primary' | 'secondary' = 'primary'
): number | null => {
const usingMathAggregationType = experimentMathAggregationForTrends()
const usingMathAggregationType = type === 'primary' ? experimentMathAggregationForTrends() : false
if (!experimentResults || !experimentResults.insight) {
return null
}
Expand Down Expand Up @@ -1416,15 +1427,31 @@ export const experimentLogic = kea<experimentLogicType>([
},
],
tabularSecondaryMetricResults: [
(s) => [s.experiment, s.secondaryMetricResults],
(experiment, secondaryMetricResults): TabularSecondaryMetricResults[] => {
(s) => [s.experiment, s.secondaryMetricResults, s.conversionRateForVariant, s.countDataForVariant],
(
experiment,
secondaryMetricResults,
conversionRateForVariant,
countDataForVariant
): TabularSecondaryMetricResults[] => {
if (!secondaryMetricResults) {
return []
}

const variantsWithResults: TabularSecondaryMetricResults[] = []
experiment?.parameters?.feature_flag_variants?.forEach((variant) => {
const metricResults: SecondaryMetricResult[] = []
experiment?.secondary_metrics?.forEach((metric, idx) => {
let result
if (metric.filters.insight === InsightType.FUNNELS) {
result = conversionRateForVariant(secondaryMetricResults?.[idx], variant.key)
} else {
result = countDataForVariant(secondaryMetricResults?.[idx], variant.key, 'secondary')
}

metricResults.push({
insightType: metric.filters.insight || InsightType.TRENDS,
result: secondaryMetricResults?.[idx]?.result?.[variant.key],
result: result || undefined,
})
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
ExperimentFunnelsQueryResponse,
ExperimentSignificanceCode,
ExperimentVariantFunnelsBaseStats,
FunnelsFilter,
FunnelsQuery,
FunnelsQueryResponse,
InsightDateRange,
Expand Down Expand Up @@ -44,13 +45,13 @@ def __init__(self, *args, **kwargs):
def calculate(self) -> ExperimentFunnelsQueryResponse:
funnels_result = self.funnels_query_runner.calculate()

self._validate_event_variants(funnels_result)

# Filter results to only include valid variants in the first step
funnels_result.results = [
result for result in funnels_result.results if result[0]["breakdown_value"][0] in self.variants
]

self._validate_event_variants(funnels_result)

# Statistical analysis
control_variant, test_variants = self._get_variants_with_base_stats(funnels_result)
probabilities = calculate_probabilities(control_variant, test_variants)
Expand Down Expand Up @@ -81,8 +82,8 @@ def _prepare_funnel_query(self) -> FunnelsQuery:
2. Configure the breakdown to use the feature flag key, which allows us
to separate results for different experiment variants.
"""
# Clone the source query
prepared_funnels_query = FunnelsQuery(**self.query.source.model_dump())
# Clone the funnels query
prepared_funnels_query = FunnelsQuery(**self.query.funnels_query.model_dump())

# Set the date range to match the experiment's duration, using the project's timezone
if self.team.timezone:
Expand All @@ -105,6 +106,10 @@ def _prepare_funnel_query(self) -> FunnelsQuery:
breakdown_type="event",
)

prepared_funnels_query.funnelsFilter = FunnelsFilter(
funnelVizType="steps",
)

return prepared_funnels_query

def _get_variants_with_base_stats(
Expand Down Expand Up @@ -185,4 +190,4 @@ def _validate_event_variants(self, funnels_result: FunnelsQueryResponse):
raise ValidationError(detail=json.dumps(errors))

def to_query(self) -> ast.SelectQuery:
raise ValueError(f"Cannot convert source query of type {self.query.source.kind} to query")
raise ValueError(f"Cannot convert source query of type {self.query.funnels_query.kind} to query")
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def test_query_runner(self):
experiment_query = ExperimentFunnelsQuery(
experiment_id=experiment.id,
kind="ExperimentFunnelsQuery",
source=funnels_query,
funnels_query=funnels_query,
)

experiment.metrics = [{"type": "primary", "query": experiment_query.model_dump()}]
Expand Down Expand Up @@ -130,7 +130,7 @@ def test_query_runner_standard_flow(self):
experiment_query = ExperimentFunnelsQuery(
experiment_id=experiment.id,
kind="ExperimentFunnelsQuery",
source=funnels_query,
funnels_query=funnels_query,
)

experiment.metrics = [{"type": "primary", "query": experiment_query.model_dump()}]
Expand Down Expand Up @@ -213,7 +213,7 @@ def test_validate_event_variants_no_events(self):
experiment_query = ExperimentFunnelsQuery(
experiment_id=experiment.id,
kind="ExperimentFunnelsQuery",
source=funnels_query,
funnels_query=funnels_query,
)

query_runner = ExperimentFunnelsQueryRunner(query=experiment_query, team=self.team)
Expand Down Expand Up @@ -255,7 +255,7 @@ def test_validate_event_variants_no_control(self):
experiment_query = ExperimentFunnelsQuery(
experiment_id=experiment.id,
kind="ExperimentFunnelsQuery",
source=funnels_query,
funnels_query=funnels_query,
)

query_runner = ExperimentFunnelsQueryRunner(query=experiment_query, team=self.team)
Expand Down Expand Up @@ -297,7 +297,7 @@ def test_validate_event_variants_no_test(self):
experiment_query = ExperimentFunnelsQuery(
experiment_id=experiment.id,
kind="ExperimentFunnelsQuery",
source=funnels_query,
funnels_query=funnels_query,
)

query_runner = ExperimentFunnelsQueryRunner(query=experiment_query, team=self.team)
Expand Down Expand Up @@ -341,7 +341,7 @@ def test_validate_event_variants_no_flag_info(self):
experiment_query = ExperimentFunnelsQuery(
experiment_id=experiment.id,
kind="ExperimentFunnelsQuery",
source=funnels_query,
funnels_query=funnels_query,
)

query_runner = ExperimentFunnelsQueryRunner(query=experiment_query, team=self.team)
Expand Down
2 changes: 1 addition & 1 deletion posthog/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -6183,12 +6183,12 @@ class ExperimentFunnelsQuery(BaseModel):
extra="forbid",
)
experiment_id: int
funnels_query: FunnelsQuery
kind: Literal["ExperimentFunnelsQuery"] = "ExperimentFunnelsQuery"
modifiers: Optional[HogQLQueryModifiers] = Field(
default=None, description="Modifiers used when performing the query"
)
response: Optional[ExperimentFunnelsQueryResponse] = None
source: FunnelsQuery


class FunnelCorrelationQuery(BaseModel):
Expand Down

0 comments on commit 1a65ec9

Please sign in to comment.