2.0.0-rc1 : Profile and achievements update.
This commit is contained in:
@@ -7,6 +7,7 @@ import json
|
||||
import argparse
|
||||
import concurrent.futures
|
||||
from collections import defaultdict, deque
|
||||
from itertools import combinations
|
||||
from typing import Optional
|
||||
|
||||
# Setup logging
|
||||
@@ -326,6 +327,14 @@ def main(force_all: bool = False, workers: int = 1, create_backup: bool = True):
|
||||
processed_ids = [str(row[0]) for row in players]
|
||||
_update_percentiles(conn_l3, processed_ids)
|
||||
_rebuild_auxiliary_marts(conn_l2, conn_l3, processed_ids)
|
||||
_rebuild_team_marts(conn_l2, conn_l3, processed_ids)
|
||||
from database.L3.processors.narrative_processor import NarrativeProcessor
|
||||
narrative_counts = NarrativeProcessor.rebuild(
|
||||
conn_l2,
|
||||
conn_l3,
|
||||
processed_ids,
|
||||
)
|
||||
logger.info("Narrative marts rebuilt: %s", narrative_counts)
|
||||
|
||||
quick_check = conn_l3.execute("PRAGMA quick_check").fetchone()[0]
|
||||
if quick_check != 'ok':
|
||||
@@ -778,6 +787,153 @@ def _calculate_record_rows(history_rows):
|
||||
return result
|
||||
|
||||
|
||||
def _rebuild_team_marts(conn_l2, conn_l3, steam_ids):
|
||||
if not steam_ids:
|
||||
return
|
||||
|
||||
conn_l3.execute('DELETE FROM dm_duo_stats')
|
||||
conn_l3.execute('DELETE FROM dm_lineup_stats')
|
||||
|
||||
all_rows = []
|
||||
for start in range(0, len(steam_ids), 400):
|
||||
chunk = steam_ids[start:start + 400]
|
||||
placeholders = ','.join('?' for _ in chunk)
|
||||
all_rows.extend(conn_l2.execute(
|
||||
f"""
|
||||
SELECT
|
||||
p.match_id,
|
||||
p.steam_id_64,
|
||||
CASE
|
||||
WHEN p.group_id IN (1, 2) THEN p.group_id
|
||||
WHEN p.team_id IN (1, 2) THEN p.team_id
|
||||
END AS team_key,
|
||||
p.rating,
|
||||
p.is_win,
|
||||
m.start_time
|
||||
FROM fact_match_players p
|
||||
JOIN fact_matches m ON m.match_id = p.match_id
|
||||
WHERE p.steam_id_64 IN ({placeholders})
|
||||
""",
|
||||
chunk,
|
||||
).fetchall())
|
||||
|
||||
match_teams = defaultdict(list)
|
||||
for row in all_rows:
|
||||
if row['team_key'] is None:
|
||||
continue
|
||||
match_teams[(row['match_id'], row['team_key'])].append(row)
|
||||
|
||||
duo_accumulator = {}
|
||||
lineup_accumulator = {}
|
||||
for rows in match_teams.values():
|
||||
players = {
|
||||
str(row['steam_id_64']): row
|
||||
for row in rows
|
||||
}
|
||||
player_ids = sorted(players)
|
||||
if len(player_ids) < 2:
|
||||
continue
|
||||
is_win = bool(next(iter(players.values()))['is_win'])
|
||||
match_date = int(next(iter(players.values()))['start_time'] or 0)
|
||||
|
||||
for player_a, player_b in combinations(player_ids, 2):
|
||||
key = (player_a, player_b)
|
||||
accumulator = duo_accumulator.setdefault(key, {
|
||||
'matches': 0,
|
||||
'wins': 0,
|
||||
'rating_a': 0.0,
|
||||
'rating_b': 0.0,
|
||||
'first': match_date,
|
||||
'last': match_date,
|
||||
})
|
||||
accumulator['matches'] += 1
|
||||
accumulator['wins'] += int(is_win)
|
||||
accumulator['rating_a'] += float(players[player_a]['rating'] or 0)
|
||||
accumulator['rating_b'] += float(players[player_b]['rating'] or 0)
|
||||
accumulator['first'] = min(accumulator['first'], match_date)
|
||||
accumulator['last'] = max(accumulator['last'], match_date)
|
||||
|
||||
for size in range(2, min(5, len(player_ids)) + 1):
|
||||
for selected_ids in combinations(player_ids, size):
|
||||
lineup_key = '|'.join(selected_ids)
|
||||
accumulator = lineup_accumulator.setdefault(lineup_key, {
|
||||
'player_ids': selected_ids,
|
||||
'matches': 0,
|
||||
'wins': 0,
|
||||
'rating': 0.0,
|
||||
'first': match_date,
|
||||
'last': match_date,
|
||||
})
|
||||
accumulator['matches'] += 1
|
||||
accumulator['wins'] += int(is_win)
|
||||
accumulator['rating'] += (
|
||||
sum(float(players[steam_id]['rating'] or 0) for steam_id in selected_ids)
|
||||
/ len(selected_ids)
|
||||
)
|
||||
accumulator['first'] = min(accumulator['first'], match_date)
|
||||
accumulator['last'] = max(accumulator['last'], match_date)
|
||||
|
||||
duo_values = []
|
||||
for (player_a, player_b), value in duo_accumulator.items():
|
||||
matches = value['matches']
|
||||
avg_a = value['rating_a'] / matches
|
||||
avg_b = value['rating_b'] / matches
|
||||
duo_values.append((
|
||||
player_a,
|
||||
player_b,
|
||||
matches,
|
||||
value['wins'],
|
||||
value['wins'] / matches,
|
||||
avg_a,
|
||||
avg_b,
|
||||
(avg_a + avg_b) / 2,
|
||||
value['first'],
|
||||
value['last'],
|
||||
1 if matches >= 5 else 0,
|
||||
))
|
||||
conn_l3.executemany(
|
||||
"""
|
||||
INSERT INTO dm_duo_stats (
|
||||
steam_id_a, steam_id_b, matches, wins, win_rate,
|
||||
avg_rating_a, avg_rating_b, avg_combined_rating,
|
||||
first_match_date, last_match_date, sample_reliable
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
duo_values,
|
||||
)
|
||||
|
||||
lineup_values = []
|
||||
for lineup_key, value in lineup_accumulator.items():
|
||||
matches = value['matches']
|
||||
lineup_values.append((
|
||||
lineup_key,
|
||||
json.dumps(value['player_ids']),
|
||||
len(value['player_ids']),
|
||||
matches,
|
||||
value['wins'],
|
||||
value['wins'] / matches,
|
||||
value['rating'] / matches,
|
||||
value['first'],
|
||||
value['last'],
|
||||
1 if matches >= 3 else 0,
|
||||
))
|
||||
conn_l3.executemany(
|
||||
"""
|
||||
INSERT INTO dm_lineup_stats (
|
||||
lineup_key, player_ids_json, player_count,
|
||||
matches, wins, win_rate, avg_team_rating,
|
||||
first_match_date, last_match_date, sample_reliable
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
lineup_values,
|
||||
)
|
||||
logger.info(
|
||||
'Team marts rebuilt: %s duos, %s lineups',
|
||||
len(duo_values),
|
||||
len(lineup_values),
|
||||
)
|
||||
|
||||
|
||||
def _update_percentiles(conn_l3, steam_ids):
|
||||
"""Calculate a real percentile among eligible players in this build."""
|
||||
if not steam_ids:
|
||||
|
||||
Reference in New Issue
Block a user