|
|
@@ -144,12 +144,13 @@ namespace molilian.core
|
|
|
/// <summary>
|
|
|
/// 曝光/点击触发:计入 Redis,失败不影响返回
|
|
|
/// </summary>
|
|
|
- public static Task<bool> TrackAsync(TrackLinkDTO link, string scene = "")
|
|
|
+ public static Task<bool> TrackAsync(TrackLinkDTO link, string scene = "", int accountId = 0)
|
|
|
{
|
|
|
|
|
|
string dateStr = DateTime.Now.ToString("yyyyMMdd");
|
|
|
string hourStr = DateTime.Now.ToString("yyyyMMddHH");
|
|
|
string metricScene = ResolveMetricScene(link, scene);
|
|
|
+ accountId = Math.Max(accountId, 0);
|
|
|
string indexValue = BuildMetricIndexValue(link.event_type, link.id, metricScene);
|
|
|
|
|
|
var metrics = new List<(string key, string indexKey, string indexValue, int expire)>
|
|
|
@@ -157,6 +158,12 @@ namespace molilian.core
|
|
|
(BuildDailyCountKey(link.event_type, link.id, dateStr, metricScene), $"{RedisPrefix}:daily:index:{dateStr}:track", indexValue, DailyExpireSeconds),
|
|
|
(BuildHourlyCountKey(link.event_type, link.id, hourStr, metricScene), $"{RedisPrefix}:hour:index:{hourStr}:track", indexValue, HourlyExpireSeconds),
|
|
|
};
|
|
|
+ if (accountId > 0)
|
|
|
+ {
|
|
|
+ string accountIndexValue = BuildMetricIndexValue(link.event_type, link.id, metricScene, accountId);
|
|
|
+ metrics.Add((BuildDailyCountKey(link.event_type, link.id, dateStr, metricScene, accountId), $"{RedisPrefix}:daily:index:{dateStr}:track", accountIndexValue, DailyExpireSeconds));
|
|
|
+ metrics.Add((BuildHourlyCountKey(link.event_type, link.id, hourStr, metricScene, accountId), $"{RedisPrefix}:hour:index:{hourStr}:track", accountIndexValue, HourlyExpireSeconds));
|
|
|
+ }
|
|
|
|
|
|
try
|
|
|
{
|
|
|
@@ -196,15 +203,17 @@ namespace molilian.core
|
|
|
foreach (var member in indexMembers)
|
|
|
{
|
|
|
var parts = member.Split('|');
|
|
|
- if (parts.Length != 2 && parts.Length != 3) continue;
|
|
|
+ if (parts.Length < 2 || parts.Length > 4) continue;
|
|
|
|
|
|
string eventType = NormalizeEventType(parts[0]);
|
|
|
if (!SupportEventTypes.Contains(eventType)) continue;
|
|
|
if (!int.TryParse(parts[1], out var trackId) || trackId <= 0) continue;
|
|
|
- bool hasScenePart = parts.Length == 3;
|
|
|
+ bool hasScenePart = parts.Length >= 3;
|
|
|
string memberScene = hasScenePart ? DecodeIndexPart(parts[2]) : string.Empty;
|
|
|
+ int accountId = 0;
|
|
|
+ if (parts.Length == 4 && (!int.TryParse(parts[3], out accountId) || accountId <= 0)) continue;
|
|
|
|
|
|
- string countKey = BuildDailyCountKey(eventType, trackId, dateStr, hasScenePart ? memberScene : string.Empty);
|
|
|
+ string countKey = BuildDailyCountKey(eventType, trackId, dateStr, hasScenePart ? memberScene : string.Empty, accountId);
|
|
|
int total = await RedisHelper.GetAsync<int>(countKey);
|
|
|
if (total <= 0) continue;
|
|
|
|
|
|
@@ -216,7 +225,7 @@ namespace molilian.core
|
|
|
}
|
|
|
|
|
|
string reportScene = ResolveMetricScene(link, memberScene);
|
|
|
- string bucketKey = BuildMetricIndexValue(eventType, trackId, reportScene);
|
|
|
+ string bucketKey = BuildMetricIndexValue(eventType, trackId, reportScene, accountId);
|
|
|
if (!buckets.TryGetValue(bucketKey, out var bucket))
|
|
|
{
|
|
|
bucket = new DailyReportBucket
|
|
|
@@ -224,6 +233,7 @@ namespace molilian.core
|
|
|
EventType = eventType,
|
|
|
TrackId = trackId,
|
|
|
Scene = reportScene,
|
|
|
+ AccountId = accountId,
|
|
|
Link = link
|
|
|
};
|
|
|
buckets[bucketKey] = bucket;
|
|
|
@@ -234,21 +244,22 @@ namespace molilian.core
|
|
|
int rows = 0;
|
|
|
foreach (var bucket in buckets.Values)
|
|
|
{
|
|
|
- await UpsertDailyReportAsync(conn, targetDate.Date, bucket.EventType, bucket.TrackId, bucket.Scene, bucket.Link, bucket.Total);
|
|
|
+ await UpsertDailyReportAsync(conn, targetDate.Date, bucket.EventType, bucket.TrackId, bucket.Scene, bucket.AccountId, bucket.Link, bucket.Total);
|
|
|
rows++;
|
|
|
}
|
|
|
return rows;
|
|
|
}
|
|
|
|
|
|
- private static Task<int> UpsertDailyReportAsync(IDbConnection conn, DateTime reportDate, string eventType, int trackId, string scene, TrackLinkDTO? link, int total)
|
|
|
+ private static Task<int> UpsertDailyReportAsync(IDbConnection conn, DateTime reportDate, string eventType, int trackId, string scene, int accountId, TrackLinkDTO? link, int total)
|
|
|
{
|
|
|
const string sql = @"
|
|
|
INSERT INTO track_daily_report
|
|
|
- (report_date, event_type, track_link_id, platform, typename, scene, unique_id, event_count, create_time, update_time)
|
|
|
+ (report_date, event_type, track_link_id, account_id, platform, typename, scene, unique_id, event_count, create_time, update_time)
|
|
|
VALUES
|
|
|
- (@reportDate, @eventType, @trackId, @platform, @typename, @scene, @uniqueId, @eventCount, @now, @now)
|
|
|
+ (@reportDate, @eventType, @trackId, @accountId, @platform, @typename, @scene, @uniqueId, @eventCount, @now, @now)
|
|
|
ON DUPLICATE KEY UPDATE
|
|
|
event_count = VALUES(event_count),
|
|
|
+ account_id = VALUES(account_id),
|
|
|
platform = VALUES(platform),
|
|
|
typename = VALUES(typename),
|
|
|
scene = VALUES(scene),
|
|
|
@@ -260,6 +271,7 @@ ON DUPLICATE KEY UPDATE
|
|
|
reportDate,
|
|
|
eventType,
|
|
|
trackId,
|
|
|
+ accountId,
|
|
|
platform = link?.platform ?? string.Empty,
|
|
|
typename = link?.typename ?? string.Empty,
|
|
|
scene,
|
|
|
@@ -269,7 +281,7 @@ ON DUPLICATE KEY UPDATE
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- public static async Task<List<TrackHourlyReportDTO>> GetHourlyReportAsync(int trackId, DateTime targetDate, string scene = "")
|
|
|
+ public static async Task<List<TrackHourlyReportDTO>> GetHourlyReportAsync(int trackId, DateTime targetDate, string scene = "", int accountId = 0)
|
|
|
{
|
|
|
var result = new List<TrackHourlyReportDTO>();
|
|
|
if (trackId <= 0) return result;
|
|
|
@@ -283,11 +295,12 @@ ON DUPLICATE KEY UPDATE
|
|
|
string metricScene = ResolveMetricScene(link, scene);
|
|
|
string linkScene = ResolveMetricScene(link, string.Empty);
|
|
|
string dateStr = targetDate.ToString("yyyyMMdd");
|
|
|
+ accountId = Math.Max(accountId, 0);
|
|
|
for (int hour = 0; hour < 24; hour++)
|
|
|
{
|
|
|
string hourStr = $"{dateStr}{hour:00}";
|
|
|
- int total = await RedisHelper.GetAsync<int>(BuildHourlyCountKey(eventType, trackId, hourStr, metricScene));
|
|
|
- if (!string.IsNullOrEmpty(metricScene) && metricScene == linkScene)
|
|
|
+ int total = await RedisHelper.GetAsync<int>(BuildHourlyCountKey(eventType, trackId, hourStr, metricScene, accountId));
|
|
|
+ if (accountId == 0 && !string.IsNullOrEmpty(metricScene) && metricScene == linkScene)
|
|
|
{
|
|
|
total += await RedisHelper.GetAsync<int>(BuildHourlyCountKey(eventType, trackId, hourStr, string.Empty));
|
|
|
}
|
|
|
@@ -300,6 +313,7 @@ ON DUPLICATE KEY UPDATE
|
|
|
typename = link.typename ?? string.Empty,
|
|
|
scene = metricScene,
|
|
|
unique_id = link.unique_id ?? string.Empty,
|
|
|
+ account_id = accountId,
|
|
|
report_date = targetDate.Date,
|
|
|
hour = hour,
|
|
|
event_count = total
|
|
|
@@ -314,28 +328,44 @@ ON DUPLICATE KEY UPDATE
|
|
|
int trackId = type == TrackType.Click ? 1 : 2;
|
|
|
if (result == null) return string.Empty;
|
|
|
string unique_id = $"1|{result.itemId}_{result.mktId}";
|
|
|
- return BuildPath(trackId, unique_id, GetTrackScene(result.parse_type, result.riskStrategy));
|
|
|
+ return BuildPath(trackId, unique_id, GetTrackScene(result.parse_type, result.riskStrategy), result.accountId);
|
|
|
}
|
|
|
public static string BuildPath(TrackType type, JdDataDTO result)
|
|
|
{
|
|
|
int trackId = type == TrackType.Click ? 19 : 20;
|
|
|
if (result == null) return string.Empty;
|
|
|
string unique_id = $"13|{result.shortLinkurl.UrlEncode()}";
|
|
|
- return BuildPath(trackId, unique_id, GetTrackScene(result.parse_type, result.riskStrategy));
|
|
|
+ return BuildPath(trackId, unique_id, GetTrackScene(result.parse_type, result.riskStrategy), result.accountId);
|
|
|
}
|
|
|
public static string BuildPath(TrackType type, PddDataDTO result)
|
|
|
{
|
|
|
int trackId = type == TrackType.Click ? 21 : 22;
|
|
|
if (result == null) return string.Empty;
|
|
|
string unique_id = $"9|{result.shortLinkurl.UrlEncode()}";
|
|
|
- return BuildPath(trackId, unique_id, GetTrackScene(result.parse_type, result.riskStrategy));
|
|
|
+ return BuildPath(trackId, unique_id, GetTrackScene(result.parse_type, result.riskStrategy), result.accountId);
|
|
|
}
|
|
|
|
|
|
- public static string BuildPath(int trackId, string unique_id = "", string scene = "")
|
|
|
+ public static string BuildBrwSimilarPath(TrackType type, TkDataDTO result, PromotionQueryItemDTO similar_goods = null, int index = 0)
|
|
|
+ {
|
|
|
+ int trackId = type == TrackType.Click ? 23 : 24;
|
|
|
+ if (result == null) return string.Empty;
|
|
|
+ string unique_id = $"1|{result.itemId}_{result.mktId}";
|
|
|
+ string scene = string.Empty;
|
|
|
+
|
|
|
+ if (similar_goods != null)
|
|
|
+ {
|
|
|
+ unique_id = $"1|{result.itemId}_{result.mktId}_{index}";
|
|
|
+ scene = "similar";
|
|
|
+ }
|
|
|
+
|
|
|
+ return BuildPath(trackId, unique_id, scene, result.accountId);
|
|
|
+ }
|
|
|
+ public static string BuildPath(int trackId, string unique_id = "", string scene = "", int accountId = 0)
|
|
|
{
|
|
|
scene = NormalizeReportScene(scene);
|
|
|
string url = $"https://api.molilian.com/tracks/track?track_id={trackId}&unique_id={unique_id}";
|
|
|
if (!string.IsNullOrEmpty(scene)) url += $"&scene={scene.UrlEncode()}";
|
|
|
+ if (accountId > 0) url += $"&account_id={accountId}";
|
|
|
return url;
|
|
|
}
|
|
|
|
|
|
@@ -477,28 +507,31 @@ ON DUPLICATE KEY UPDATE
|
|
|
return DefaultDimensionValue;
|
|
|
}
|
|
|
|
|
|
- private static string BuildDailyCountKey(string eventType, int trackId, string dateStr, string scene)
|
|
|
+ private static string BuildDailyCountKey(string eventType, int trackId, string dateStr, string scene, int accountId = 0)
|
|
|
{
|
|
|
eventType = NormalizeEventType(eventType);
|
|
|
scene = NormalizeReportScene(scene);
|
|
|
string key = $"{RedisPrefix}:daily:{eventType}:{trackId}:{dateStr}";
|
|
|
if (!string.IsNullOrEmpty(scene)) key += $":{EncodeIndexPart(scene)}";
|
|
|
+ if (accountId > 0) key += $":account:{accountId}";
|
|
|
return key;
|
|
|
}
|
|
|
|
|
|
- private static string BuildHourlyCountKey(string eventType, int trackId, string hourStr, string scene)
|
|
|
+ private static string BuildHourlyCountKey(string eventType, int trackId, string hourStr, string scene, int accountId = 0)
|
|
|
{
|
|
|
eventType = NormalizeEventType(eventType);
|
|
|
scene = NormalizeReportScene(scene);
|
|
|
string key = $"{RedisPrefix}:hour:{eventType}:{trackId}:{hourStr}";
|
|
|
if (!string.IsNullOrEmpty(scene)) key += $":{EncodeIndexPart(scene)}";
|
|
|
+ if (accountId > 0) key += $":account:{accountId}";
|
|
|
return key;
|
|
|
}
|
|
|
|
|
|
- private static string BuildMetricIndexValue(string eventType, int trackId, string scene)
|
|
|
+ private static string BuildMetricIndexValue(string eventType, int trackId, string scene, int accountId = 0)
|
|
|
{
|
|
|
eventType = NormalizeEventType(eventType);
|
|
|
scene = NormalizeReportScene(scene);
|
|
|
+ if (accountId > 0) return $"{eventType}|{trackId}|{EncodeIndexPart(scene)}|{accountId}";
|
|
|
if (string.IsNullOrEmpty(scene)) return $"{eventType}|{trackId}";
|
|
|
return $"{eventType}|{trackId}|{EncodeIndexPart(scene)}";
|
|
|
}
|
|
|
@@ -525,6 +558,7 @@ ON DUPLICATE KEY UPDATE
|
|
|
public string EventType { get; set; } = string.Empty;
|
|
|
public int TrackId { get; set; }
|
|
|
public string Scene { get; set; } = string.Empty;
|
|
|
+ public int AccountId { get; set; }
|
|
|
public TrackLinkDTO? Link { get; set; }
|
|
|
public int Total { get; set; }
|
|
|
}
|