Skip to content

Commit

Permalink
拡張集計のキャッシュ機能を追加
Browse files Browse the repository at this point in the history
  • Loading branch information
kmycode committed Sep 9, 2022
1 parent b06fe7e commit 6404564
Show file tree
Hide file tree
Showing 16 changed files with 768 additions and 468 deletions.
4 changes: 2 additions & 2 deletions KmyKeiba/Models/Analysis/RaceFinderTrendAnalysisSelector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ public class RaceHorseTrendAnalysisSelectorWrapper : TrendAnalysisSelector<RaceH
{
public override string Name { get; } = string.Empty;
public override RaceData Race { get; } = new();
private readonly RaceFinder _finder;
private readonly IRaceFinder _finder;

public RaceHorseTrendAnalysisSelectorWrapper(RaceFinder finder)
public RaceHorseTrendAnalysisSelectorWrapper(IRaceFinder finder)
{
this._finder = finder;
base.OnFinishedInitialization();
Expand Down
160 changes: 160 additions & 0 deletions KmyKeiba/Models/Race/AnalysisTable/AggregateRaceFinder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
using KmyKeiba.Data.Db;
using KmyKeiba.Models.Analysis;
using KmyKeiba.Models.Race.Finder;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace KmyKeiba.Models.Race.AnalysisTable
{
public class AggregateRaceFinder
{
private readonly List<CacheItem> _caches = new();

public async Task<RaceHorseFinderQueryResult> FindRaceHorsesAsync(string keys, int sizeMax, RaceHorseAnalyzer horse)
{
var reader = new ScriptKeysReader(keys);
var queries = reader.GetQueries(horse);

var relations = queries.QueryValueRelations;
var currentRaceKeys = relations.Where(r => r.Type == QueryValueRelationType.CurrentRaceValue).Select(r => r.Key).ToList();
var canUseCache = true;

if (relations.Any(r => r.Type == QueryValueRelationType.CurrentRaceValue || r.Type == QueryValueRelationType.CurrentRaceItem))
{
var enableKeys = new[]
{
QueryKey.Course,
QueryKey.Condition,
QueryKey.Weather,
QueryKey.Popular,
QueryKey.Distance,
QueryKey.RunningStyle,
QueryKey.HorseNumber,
QueryKey.FrameNumber,
QueryKey.RiderCode,
QueryKey.RiderName,
QueryKey.TrainerCode,
QueryKey.TrainerName,
QueryKey.Subject,
};
if (!currentRaceKeys.All(c => enableKeys.Contains(c)))
{
canUseCache = false;
}

if (canUseCache)
{
var caches = this._caches.Where(c => c.Keys == keys && c.Horse.Race.StartTime < horse.Race.StartTime.AddMonths(3)).ToArray();
if (caches.Any())
{
foreach (var cache in caches)
{
var ch = cache.Horse;
canUseCache = true;

foreach (var key in currentRaceKeys)
{
switch (key)
{
case QueryKey.Course:
canUseCache = ch.Race.Course == horse.Race.Course;
break;
case QueryKey.Condition:
canUseCache = ch.Race.TrackCondition == horse.Race.TrackCondition;
break;
case QueryKey.Weather:
canUseCache = ch.Race.TrackWeather == horse.Race.TrackWeather;
break;
case QueryKey.Popular:
canUseCache = ch.Data.Popular == horse.Data.Popular;
break;
case QueryKey.Distance:
canUseCache = ch.Race.Distance == horse.Race.Distance;
break;
case QueryKey.Subject:
canUseCache = ch.Race.SubjectAgeYounger == horse.Race.SubjectAgeYounger &&
ch.Race.SubjectDisplayInfo == horse.Race.SubjectDisplayInfo;
break;
case QueryKey.RunningStyle:
canUseCache = ch.History?.RunningStyle == horse.History?.RunningStyle;
break;
case QueryKey.FrameNumber:
canUseCache = ch.Data.FrameNumber == horse.Data.FrameNumber;
break;
case QueryKey.HorseNumber:
canUseCache = ch.Data.Number == horse.Data.Number;
break;
case QueryKey.RiderCode:
canUseCache = ch.Data.RiderCode == horse.Data.RiderCode;
break;
case QueryKey.RiderName:
canUseCache = ch.Data.RiderName == horse.Data.RiderName;
break;
case QueryKey.TrainerCode:
canUseCache = ch.Data.TrainerCode == horse.Data.TrainerCode;
break;
case QueryKey.TrainerName:
canUseCache = ch.Data.TrainerName == horse.Data.TrainerName;
break;
}

if (!canUseCache)
{
break;
}
}

if (canUseCache && cache?.QueryResult != null)
{
return cache.QueryResult;
}
}
}
}
}
else
{
var cache = this._caches.FirstOrDefault(c => c.Keys == keys);
if (cache?.QueryResult != null)
{
return cache.QueryResult;
}
}

using var finder = new PureRaceFinder(horse);
var result = await finder.FindRaceHorsesAsync(queries, sizeMax);

if (canUseCache)
{
lock (this._caches)
{
this._caches.Add(new CacheItem(keys, currentRaceKeys, horse, result));
}
}

return result;
}

private class CacheItem
{
public string Keys { get; }

public IReadOnlyList<QueryKey> CurrentRaceValues { get; }

public RaceHorseAnalyzer Horse { get; }

public RaceHorseFinderQueryResult QueryResult { get; }

public CacheItem(string keys, IReadOnlyList<QueryKey> qkeys, RaceHorseAnalyzer horse, RaceHorseFinderQueryResult result)
{
this.Keys = keys;
this.CurrentRaceValues = qkeys;
this.Horse = horse;
this.QueryResult = result;
}
}
}
}
4 changes: 2 additions & 2 deletions KmyKeiba/Models/Race/AnalysisTable/AnalysisTableAggregater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public void BeginLoad()
Task.Run(async () => await this.LoadAsync());
}

public async Task LoadAsync(bool isBulk = false)
public async Task LoadAsync(bool isBulk = false, AggregateRaceFinder? aggregateFinder = null)
{
this.IsLoading.Value = true;

Expand Down Expand Up @@ -86,7 +86,7 @@ public async Task LoadAsync(bool isBulk = false)
{
IDisposable progress = table.Table.Progress.Subscribe(v => this.Progress.Value = lastTableProgress + v);

await this._model.AnalysisTableAsync(table.Table, isBulk);
await this._model.AnalysisTableAsync(table.Table, isBulk, aggregateFinder);

progress.Dispose();
lastTableProgress += table.Table.Progress.Value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,19 @@ namespace KmyKeiba.Models.Race.AnalysisTable
internal class AnalysisTableBulkEngine : IScriptBulkEngine
{
private static readonly log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod()!.DeclaringType);
private readonly AggregateRaceFinder _aggregateFinder;

public ReactiveProperty<ReactiveProperty<int>?> ProgressMax { get; } = new();

public ReactiveProperty<ReactiveProperty<int>?> Progress { get; } = new();

public bool IsFinished { get; set; }

public AnalysisTableBulkEngine(AggregateRaceFinder aggregateFinder)
{
this._aggregateFinder = aggregateFinder;
}

public void Dispose()
{
}
Expand Down Expand Up @@ -56,7 +62,7 @@ public async Task DoAsync(ScriptBulkModel model, IEnumerable<ScriptResultItem> i

this.Progress.Value = info.AnalysisTable.Value.Aggregate.Progress;
this.ProgressMax.Value = info.AnalysisTable.Value.Aggregate.ProgressMax;
await info.AnalysisTable.Value.Aggregate.LoadAsync(isBulk: true);
await info.AnalysisTable.Value.Aggregate.LoadAsync(isBulk: true, this._aggregateFinder);

// TODO: 買い目処理はここに
//if (info.Tickets.Value != null && info.Payoff != null)
Expand Down
4 changes: 2 additions & 2 deletions KmyKeiba/Models/Race/AnalysisTable/AnalysisTableModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public async Task AnalysisTableWithReloadAsync(AnalysisTableSurface table)
await this.AnalysisTableAsync(table);
}

public async Task AnalysisTableAsync(AnalysisTableSurface table, bool isBulk = false)
public async Task AnalysisTableAsync(AnalysisTableSurface table, bool isBulk = false, AggregateRaceFinder? aggregateFinder = null)
{
//this.ReloadTables();
var newTable = this.Tables.FirstOrDefault(t => t.Data.Id == table.Data.Id);
Expand All @@ -139,7 +139,7 @@ public async Task AnalysisTableAsync(AnalysisTableSurface table, bool isBulk = f
}

using var db = new MyContext();
await newTable.AnalysisAsync(db, this._finders, this.Weights, false, isBulk);
await newTable.AnalysisAsync(db, this._finders, this.Weights, false, isBulk, aggregateFinder);
}

public AnalysisTableCache ToCache()
Expand Down
15 changes: 13 additions & 2 deletions KmyKeiba/Models/Race/AnalysisTable/AnalysisTableRow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ void UpdateOutput(AnalysisTableRowOutputItem? output)
this._isInitialized = true;
}

public async Task LoadAsync(RaceData race, IReadOnlyList<RaceFinder> finders, IReadOnlyList<AnalysisTableWeight> weights, bool isCacheOnly = false, bool isBilk = false)
public async Task LoadAsync(RaceData race, IReadOnlyList<RaceFinder> finders, IReadOnlyList<AnalysisTableWeight> weights, bool isCacheOnly = false, bool isBilk = false, AggregateRaceFinder? aggregateFinder = null)
{
this.IsLoaded.Value = false;
this.IsLoading.Value = true;
Expand Down Expand Up @@ -416,6 +416,7 @@ public async Task LoadAsync(RaceData race, IReadOnlyList<RaceFinder> finders, IR
query += "|datastatus=5-7";
}

// レース画面を開いたとき、自動でキャッシュからデータを読み込む(Finderキャッシュ機能が削除されたので現在はデッドコードである)
var cache = item.Finder.TryFindRaceHorseCache(query);
if (cache != null)
{
Expand Down Expand Up @@ -630,7 +631,17 @@ public async Task LoadAsync(RaceData race, IReadOnlyList<RaceFinder> finders, IR
}
else
{
var source = await item.Finder.FindRaceHorsesAsync(query, size, withoutFutureRaces: true, withoutFutureRacesForce: true);
RaceHorseFinderQueryResult source;
if (aggregateFinder != null && (this.Data.Output == AnalysisTableRowOutputType.PlaceBetsRate ||
this.Data.Output == AnalysisTableRowOutputType.RecoveryRate ||
this.Data.Output == AnalysisTableRowOutputType.WinRate))
{
source = await aggregateFinder.FindRaceHorsesAsync(keys, size, item.Cell.Horse);
}
else
{
source = await ((IRaceFinder)item.Finder).FindRaceHorsesAsync(query, size, withoutFutureRaces: true, withoutFutureRacesForce: true);
}
this.AnalysisSource(source, myWeights, item.Cell, item.Finder);
}
});
Expand Down
4 changes: 2 additions & 2 deletions KmyKeiba/Models/Race/AnalysisTable/AnalysisTableSurface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,15 @@ public void UpdateRows()
this.ProgressMax.Value = this.Rows.Count;
}

public async Task AnalysisAsync(MyContext db, IReadOnlyList<RaceFinder> finders, IReadOnlyList<AnalysisTableWeight> weights, bool isCacheOnly, bool isBulk = false)
public async Task AnalysisAsync(MyContext db, IReadOnlyList<RaceFinder> finders, IReadOnlyList<AnalysisTableWeight> weights, bool isCacheOnly, bool isBulk = false, AggregateRaceFinder? aggregateFinder = null)
{
this.IsLoading.Value = true;
this.ProgressMax.Value = this.Rows.Count;
this.Progress.Value = 0;

foreach (var row in this.Rows.OrderBy(r => r.Data.Output == AnalysisTableRowOutputType.Binary ? 0 : 1))
{
await row.LoadAsync(this.Race, finders, weights, isCacheOnly, isBulk);
await row.LoadAsync(this.Race, finders, weights, isCacheOnly, isBulk, aggregateFinder);
this.Progress.Value++;
}

Expand Down
8 changes: 4 additions & 4 deletions KmyKeiba/Models/Race/Finder/FinderModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public void BeginLoad()
try
{
this.Columns.Value = this.RaceHorseColumns;
var data = await this._finder.FindRaceHorsesAsync(this.Keys.Value, 3000);
var data = await ((IRaceFinder)this._finder).FindRaceHorsesAsync(this.Keys.Value, 3000);
var allItems = data.AsItems();

IEnumerable<IEnumerable<FinderRaceHorseItem>> SplitData(int size)
Expand Down Expand Up @@ -356,7 +356,7 @@ internal Task<FinderQueryResult<RaceAnalyzer>> FindRacesAsync(string keys, int c

internal Task<RaceHorseFinderQueryResult> FindRaceHorsesAsync(string keys, int count, int offset)
{
return this._finder.FindRaceHorsesAsync(keys, count, offset);
return ((IRaceFinder)this._finder).FindRaceHorsesAsync(keys, count, offset);
}

private void UpdateExpandedData(IEnumerable<FinderRaceHorseGroupItem> groups)
Expand Down Expand Up @@ -428,12 +428,12 @@ private void OnTabChanged()

public void ReplaceFrom(FinderModel model)
{
this._finder.ReplaceFrom(model._finder);
this._finder.CopyFrom(model._finder);
}

public void ReplaceFrom(RaceFinder finder)
{
this._finder.ReplaceFrom(finder);
this._finder.CopyFrom(finder);
}

public void ClearCache()
Expand Down
Loading

0 comments on commit 6404564

Please sign in to comment.