Add string interning analysis and recent data filtering

- Add using directives for binary and JSON serializers.
- Reformat and clarify Hungarian documentation comments.
- Add GetAnalyzeStringInternCandidatesLog test (DEBUG only) to analyze string interning opportunities in recent orders.
- Filter OrderDtoToToon test data to only include orders and shippings from the last 70 days.
- Improves test relevance and adds diagnostics for serialization efficiency.
This commit is contained in:
Loretta 2026-01-26 10:23:43 +01:00
parent f369491a1d
commit 22bda45ade
1 changed files with 62 additions and 40 deletions

View File

@ -1,6 +1,8 @@
using AyCode.Core.Enums; using AyCode.Core.Enums;
using AyCode.Core.Extensions; using AyCode.Core.Extensions;
using AyCode.Core.Loggers; using AyCode.Core.Loggers;
using AyCode.Core.Serializers.Binaries;
using AyCode.Core.Serializers.Jsons;
using AyCode.Core.Serializers.Toons; using AyCode.Core.Serializers.Toons;
using FruitBank.Common; using FruitBank.Common;
using FruitBank.Common.Dtos; using FruitBank.Common.Dtos;
@ -14,67 +16,69 @@ using Nop.Core.Domain.Common;
using Nop.Core.Domain.Orders; using Nop.Core.Domain.Orders;
using Nop.Core.Domain.Payments; using Nop.Core.Domain.Payments;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Text;
namespace FruitBankHybrid.Shared.Tests; namespace FruitBankHybrid.Shared.Tests;
1. "Headered List" (A biztonságos táblázatosítás) //1. "Headered List" (A biztonságos táblázatosítás)
Az LLM-eknek nem kell minden sorban megismételni a mezőneveket, ha a lista elején egyszer definiálod a sorrendet. Ez nem találgatás, hanem egy lokális "szerződés". //Az LLM-eknek nem kell minden sorban megismételni a mezőneveket, ha a lista elején egyszer definiálod a sorrendet. Ez nem találgatás, hanem egy lokális "szerződés".
Hagyományos (pazarló): //Hagyományos (pazarló):
Kódrészlet //Kódrészlet
OrderItemDtos = [ //OrderItemDtos = [
OrderItemDto { Id = 120, Quantity = 10, ProductName = "Áfonya" } // OrderItemDto { Id = 120, Quantity = 10, ProductName = "Áfonya" }
OrderItemDto { Id = 121, Quantity = 5, ProductName = "Narancs" } // OrderItemDto { Id = 121, Quantity = 5, ProductName = "Narancs" }
] //]
Optimalizált (pontos és tömör): //Optimalizált (pontos és tömör):
Kódrészlet //Kódrészlet
OrderItemDtos: OrderItemDto[] = [ //OrderItemDtos: OrderItemDto[] = [
[ Id, Quantity, ProductName ] // [ Id, Quantity, ProductName ]
[ 120, 10, "Áfonya" ] // [ 120, 10, "Áfonya" ]
[ 121, 5, "Narancs" ] // [ 121, 5, "Narancs" ]
] //]
Miért ez? Az LLM a fejléc alapján (mint egy CSV-nél) rendeli hozzá az értékeket a típushoz. Mivel a típus (OrderItemDto) ott van a definícióban, a szemantikai kapcsolat nem vész el. // Miért jó ez? Az LLM a fejléc alapján (mint egy CSV-nél) rendeli hozzá az értékeket a típushoz. Mivel a típus (OrderItemDto) ott van a definícióban, a szemantikai kapcsolat nem vész el.
2. Típus-öröklődés a listákban //2. Típus-öröklődés a listákban
Ha a @types részben már leírtad, hogy az OrderItemDto.ProductDto mezője egy ProductDto típust vár, akkor a @data részben felesleges kiírni a típusnevet minden egyes elemnél. //Ha a @types részben már leírtad, hogy az OrderItemDto.ProductDto mezője egy ProductDto típust vár, akkor a @data részben felesleges kiírni a típusnevet minden egyes elemnél.
Példa: //Példa:
Kódrészlet //Kódrészlet
// A 'ProductDto' elhagyható az objektum elől, mert a sémából tudja //// A 'ProductDto' elhagyható az objektum elől, mert a sémából tudja
ProductDto = { //ProductDto = {
Id = 1 // Id = 1
Name = "Áfonya..." // Name = "Áfonya..."
GenericAttributes = [ // GenericAttributes = [
{ Id = 99, Key = "NetWeight", Value = "178.3" } // { Id = 99, Key = "NetWeight", Value = "178.3" }
{ Id = 100, Key = "GrossWeight", Value = "19" } // { Id = 100, Key = "GrossWeight", Value = "19" }
] // ]
} //}
3. Alapértelmezett értékek elhagyása (Implicit Defaults) //3. Alapértelmezett értékek elhagyása (Implicit Defaults)
Ha egy mező értéke megegyezik a @types-ban definiált default-value-val, vagy null/0/false, akkor azt teljesen hagyd ki a @data részből. //Ha egy mező értéke megegyezik a @types-ban definiált default-value-val, vagy null/0/false, akkor azt teljesen hagyd ki a @data részből.
Szabály: Ami nincs ott, az az alapértelmezett. // Szabály: Ami nincs ott, az az alapértelmezett.
Token megtakarítás: A FruitBank példádban a GenericAttributes = <GenericAttributeDto[]> (count: 0) [] sorok rengeteg helyet foglalnak. Ha üres, egyszerűen ne küldd el a mezőt. // Token megtakarítás: A FruitBank példádban a GenericAttributes = <GenericAttributeDto[]> (count: 0) [] sorok rengeteg helyet foglalnak. Ha üres, egyszerűen ne küldd el a mezőt.
4. String Table helyett: "Object Anchoring" //4. String Table helyett: "Object Anchoring"
használd az objektum-referenciákat (amit a @ProductDto:1 jelöléssel már el is kezdett a rendszered). //használd az objektum-referenciákat (amit a @ProductDto:1 jelöléssel már el is kezdett a rendszered).
Ha ugyanaz a Product szerepel 5 különböző rendelési tételnél, ne írd le ötször. //Ha ugyanaz a Product szerepel 5 különböző rendelési tételnél, ne írd le ötször.
Első alkalommal: ProductDto { ... } // Első alkalommal: ProductDto { ... }
Minden további alkalommal: ProductDto = @ProductDto:1 // Minden további alkalommal: ProductDto = @ProductDto:1
//[ToonIgnore][ToonDataIgnore] //[ToonIgnore][ToonDataIgnore]
[ToonDescription(Purpose = "Container model for Shipping, Order")] [ToonDescription(Purpose = "Container model for Shipping, Order")]
@ -103,13 +107,31 @@ public sealed class ToonTests
}); });
} }
#if DEBUG
[TestMethod]
public async Task GetAnalyzeStringInternCandidatesLog()
{
var orders = (await _signalRClient.GetAllOrderDtos())!.Where(x=>x.CreatedOnUtc > DateTime.UtcNow.AddDays(-70)).ToList();
var options = AcBinarySerializerOptions.WithoutReferenceHandling;
//options.SetReferenceHandlingUnsafe(ReferenceHandlingMode.OnlyId);
var analysisLog = AcBinarySerializer.GetAnalyzeStringInternCandidatesLog(orders, options);
Assert.IsNotNull(analysisLog);
Assert.IsGreaterThan(0, analysisLog.Length);
// Print results sorted by occurrence count
Console.WriteLine(analysisLog.ToString());
Console.WriteLine();
}
#endif
[TestMethod] [TestMethod]
public async Task OrderDtoToToon() public async Task OrderDtoToToon()
{ {
var a = new FullProcessModel(); var a = new FullProcessModel();
a.Orders = (await _signalRClient.GetAllOrderDtos())!; a.Orders = (await _signalRClient.GetAllOrderDtos())!.Where(x=>x.CreatedOnUtc > DateTime.UtcNow.AddDays(-70)).ToList();
a.Shippings = (await _signalRClient.GetShippings())!; a.Shippings = (await _signalRClient.GetShippings())!.Where(x=>x.Created > DateTime.UtcNow.AddDays(-70)).ToList();
var toon = AcToonSerializer.Serialize(a, FruitBankConstClient.DomainDescription, AcToonSerializerOptions.Default); var toon = AcToonSerializer.Serialize(a, FruitBankConstClient.DomainDescription, AcToonSerializerOptions.Default);