शून्य पीआई ग्राहक इंटेलिजेंस
में भाग 1 हम दर्शन और श्रृंखला की समीक्षा भाग 1.1 हमने नमूना डेटा जनरेटर बना लिया
इस भाग पर ध्यान केंद्रित है
- Zero-PII प्रोफ़ाइल वास्तुकला - अल्पावधि सत्रों के विपरीत स्थायी प्रोफाइल
- संकेत और वजन - क्या हम ट्रैक करते हैं और यह कैसे एकत्रित होता है
- खण्ड परिभाषाएँ - भारित नियमों के साथ अस्पष्ट सदस्यता
- आउटबॉक्स पैटर्न पूर्वावलोकन विश्वसनीय घटना प्रकाशन (भाग में विस्तृत है
यह है नमूना परियोजना (Mostlylucid.SegmentCommerceएक छोटा ई-कॉमर्स डेमो जो कोर पैटर्न दिखाता है।
इसे एकल में उत्पादन पैटर्न के रूप में सोचें
प्रौद्योगिकी विकल्प
हमने एक चुन लिया सरल, कोहेजिव स्टैक उत्पादन पैटर्नों को प्रदर्शित करते समय नमूना साफ रखने के लिए
PostgreSQL + pgvector: एक डाटाबेस
अलग सदिश डाटाबेसों के बजाय message queues पोस्टग्रेएसक्यूएल:
flowchart LR
App[ASP.NET Core] --> PG[(PostgreSQL)]
PG --> JSONB[JSONB<br/>interests]
PG --> Vector[pgvector<br/>embeddings]
PG --> Queue[Queue tables<br/>jobs, outbox]
PG --> FTS[Full-text<br/>tsvector]
style PG stroke:#2f9e44,stroke-width:3px
style JSONB stroke:#1971c2,stroke-width:2px
style Vector stroke:#1971c2,stroke-width:2px
style Queue stroke:#1971c2,stroke-width:2px
style FTS stroke:#1971c2,stroke-width:2px
- JSONB लचीला स्कीमा के लिए (न कोई अलग NoSQL
- पीजीवेक्टर अंतःकरण के लिए (नहीं Qdrant
- सुनें रोजगार के लिए (no RedisM SK1RabbitMQ)
- tsvectorGenericName पूरा के लिए-पाठ (नहीं Elasticsearch
एक कनेक्शन पूल. एक बैकअप
HTMX + Alpine.jsM SK2 सर्वर -प्रचालित यूआई
<!-- Instant search (no page reload) -->
<input
hx-get="/api/search"
hx-trigger="keyup changed delay:300ms"
hx-target="#results" />
- HTMXसर्वर आंशिक रेंडर करता है
- एल्पीन: निर्माण चरण के बिना प्रतिक्रिया
- प्रगतिशील वृद्धिJS के बिना काम करता है
सर्वर के साथ UX जैसे SPA
ASP.NET Core: वितरण योग्य पैटर्न
एकल अनुप्रयोग
- आउटबॉक्स संदेश बस के लिए swap
- कार्य कतार (LISTEN/NOTIFY
- सत्र संग्रहक अलग API के लिए → स्वैप
सरल प्रारंभ करें. आवश्यकता पड़ने पर वितरित करें
हमने जो बचा लिया
- कोई अलग भेक्टर डाटाबेस नहीं है (pgvector को स्थानांतरित किया गया है
- कोई JS फ्रेमवर्क नहीं है
- अभी तक कोई माइक्रो सर्विस नहीं है ( पैटर्न मोनोलिथ या वितरित में काम करते हैं
- कोई डॉकर फैलाव कम्पोज करें (one DB, one appM SK2
Zero-PII चुनौती
पारंपरिक उपयोक्ता ट्रैकिंग पहचान योग्य सूचना stores identifiable information: names, emailsM SK2 behavior linked to user IDs
हम बर्ताव पैटर्न store behavioral patterns
flowchart LR
subgraph "Traditional Approach"
User1[User: [email protected]] --> Behavior1[Bought headphones]
Behavior1 --> PII1[(PII Database)]
end
subgraph "Zero-PII Approach"
User2[Anonymous Session] --> Behavior2[Bought headphones]
Behavior2 --> Pattern[(Category: tech<br/>Signal weight: 1.0)]
end
style PII1 stroke:#c92a2a,stroke-width:3px
style Pattern stroke:#2f9e44,stroke-width:3px
प्रमुख अंतर्दृष्टि आप को यह जानने की जरूरत नहीं है कि कौन कोई है पता करने के लिए वे क्या चाहते हैं.
वास्तुकला की समीक्षा
प्रणाली में तीन कोर परतें हैं
flowchart TB
Browser[Browser] --> Session[Session Collector]
Session --> Profile[Persistent Profile]
Profile --> Segments[Segment Service]
Session -->|in-memory only| Cache[(IMemoryCache)]
Profile -->|elevated signals| DB[(PostgreSQL + JSONB)]
Segments -->|memberships| UI[Segment Explorer UI]
style Session stroke:#1971c2,stroke-width:3px
style Profile stroke:#2f9e44,stroke-width:3px
style Segments stroke:#fab005,stroke-width:3px
style Cache stroke:#e64980,stroke-width:2px
- सत्र संकलक व्यवहारिक संकेतों को ग्रहण करता है केवल स्मृति में
- स्थायी प्रोफ़ाइल उच्च को बढ़ाता है डाटाबेस-backed
- खण्ड सेवा - नियमों के विरुद्ध प्रोफाइल का मूल्यांकन करता है
आलोचनात्मक विभेदSessions are ephemeral
सत्र प्रोफ़ाइलें: Strict In-Memory | ( | LFU Cache |)
सत्र हैं पूरी तरह मेमोरी में. वे यहाँ रहते हैं IMemoryCache स्लाइडिंग समाप्ति के साथ और डाटाबेस को कभी नहीं छुए.
यह एक कठोर वास्तुकला अवरोध है।
सत्र प्रोफ़ाइल: इन-स्मरण मॉडल
// Mostlylucid.SegmentCommerce/Models/SessionProfile.cs
public class SessionProfile
{
public string SessionKey { get; set; } = string.Empty;
// Category interest scores: { "tech": 0.75, "fashion": 0.25 }
public Dictionary<string, double> Interests { get; set; } = new();
// Detailed signal counts: { "tech": { "product_view": 5, "add_to_cart": 1 } }
public Dictionary<string, Dictionary<string, int>> Signals { get; set; } = new();
// Products viewed this session
public List<int> ViewedProducts { get; set; } = new();
// Session context (device, referrer domain, time-of-day)
public SessionContext? Context { get; set; }
// Aggregates
public double TotalWeight { get; set; }
public int SignalCount { get; set; }
public int PageViews { get; set; }
public int ProductViews { get; set; }
public int CartAdds { get; set; }
// Timestamps
public DateTime StartedAt { get; set; } = DateTime.UtcNow;
public DateTime LastActivityAt { get; set; } = DateTime.UtcNow;
// Link to persistent profile (if fingerprint resolved)
public Guid? PersistentProfileId { get; set; }
}
स्लाइडिंग समाप्ति के साथ IMemoryCache (or IDistributedCache) में भंडारित
// Mostlylucid.SegmentCommerce/Services/Profiles/SessionCollector.cs
_cache.Set(sessionKey, sessionProfile, new MemoryCacheEntryOptions
{
SlidingExpiration = TimeSpan.FromMinutes(30),
Priority = CacheItemPriority.Normal, // LFU eviction under memory pressure
// CRITICAL: Eviction callback decides whether to elevate to persistent profile
PostEvictionCallbacks =
{
new PostEvictionCallbackRegistration
{
EvictionCallback = async (key, value, reason, state) =>
{
if (value is SessionProfile session && ShouldElevate(session))
{
// Only NOW do we write to database (persistent profile)
await ElevateToProfileAsync(session);
}
// Otherwise: session is gone forever
}
}
}
});
कठोर प्रतिबंध
- अनियमित निरंतरता शून्य: सत्र प्रत्यक्ष केवल कैश में (IMemoryCache या IDistributedCache जैसे Redis
- एलएफयू निष्कासन: कम-सेंशन का उपयोग स्मृति दबाव के तहत पहले बाहर निकालें
- स्लाइडिंग समाप्तिपिछले क्रियाकलाप से मिनट
- बहिष्कार कॉलबैक: उच्च ऊँचा ऊँचाई को बढ़ाने का अंतिम मौका - मूल्य संकेतों से पहले कि वे हृ हृ खो गए
- कोई पुनर्प्राप्ति नहींअनुप्रयोग फिर से आरंभ करें = सभी सत्र नष्ट हो गए हैं
उत्थान निर्णय (उत्थान के बारे में
private bool ShouldElevate(SessionProfile session)
{
// Elevate if:
// - User added to cart (high intent)
// - User completed purchase (conversion)
// - Fingerprint was resolved (identity established)
// - Session weight exceeds threshold (engaged visitor)
return session.CartAdds > 0
|| session.TotalWeight > 5.0
|| session.PersistentProfileId.HasValue;
}
क्यों निर्वासन कॉलबैक
यह है केवल निरंतरता तय करने के लिए सुरक्षित बिन्दु
- हम पूरी सत्र इतिहास जानते हैं
- हम समग्र भागीदारी का मूल्यांकन कर सकते हैं
- हम कम मौज़ूद सत्रों को संग्रहित करने से बचते हैं
- हम सत्रों की गारंटी don'\t दुर्घटनावश जारी रखें
अगर हम बाहर निकालने के दौरान ऊँचाई नहीं करते हैं सदा के लिए चला गयायह डिजाइन है
SessionContext: जो हम ट्रैक करते हैं
public class SessionContext
{
public string? DeviceType { get; set; } // "mobile", "desktop"
public string? EntryPath { get; set; } // "/products/tech" (no query params)
public string? ReferrerDomain { get; set; } // "google.com" (domain only, not full URL)
public string? TimeOfDay { get; set; } // "morning", "afternoon"
public string? DayType { get; set; } // "weekday", "weekend"
}
क्या ध्यान दें नहीं यहाँ: आईपी पताों, उपयोक्ता एजेंटों , पूर्ण यूआरएल्सM SK3 ट्रैकिंग पिक्सेलों. हम पकड़ें संदर्भ पैटर्न, पहचान योग्य सूचना नहीं है
संकेत क्या हैं
ए संकेत एक उपयोक्ता क्रिया के दौरान पकड़ा गया एक व्यवहारिक तथ्य है
इस अवधारणा से आता है अल्पावधि संकेत-\ short\ -\ living facts that exist in a bounded window and age out naturally "api.rate_limited" या "gateway.slow" कड़ी कuppling के बिना व्यवहार को समन्वयित करना.
यहाँ हम उपयोगकर्ता व्यवहार के लिए एक ही पैटर्न लागू करें
- उत्पाद दृश्य →
product_viewसंकेत (भार - गाड़ी में जोड़ें →
add_to_cartसंकेत (भार - खरीद →
purchaseसंकेत (भार
संकेत हैं अल्पकालिक सत्र के साथ समाप्त होना 0-PII (नहीं पहचान भारित (
क्लाइंट फ़िंगरप्रिंटिंग (Zero-क्विकी पहचान
ट्रैकिंग कुकीज़ के बिना सत्रों को लिंक करने के लिए हम प्रयोग करते हैं क्लाइंट-साइड अंगुल छापब्राउज़र संकेतों से एक हैश संगणित करता है सिर्फ हैश के लिए /api/fingerprint.
तब सर्वर एचएमसी जो हैश एक गुप्त कुंजी के साथ
यह कोड मेरी से अनुकूलित है बोट खोज परियोजना, जहां यह है' scrapers को पहचानने के लिए उपयोग किया जाता है।
// Mostlylucid.SegmentCommerce/ClientFingerprint/fingerprint.js
// Collect signals (browser capabilities, not PII)
var signals = [
Intl.DateTimeFormat().resolvedOptions().timeZone,
navigator.language,
screen.width + 'x' + screen.height,
// ... (see full code)
];
// Hash locally
var hash = hash(signals.join('|'));
// Send only the hash via sendBeacon
navigator.sendBeacon('/api/fingerprint', JSON.stringify({ h: hash }));
सर्वर
// Server HMACs the client hash with a secret key
var profileKey = HMACSHA256(clientHash + secretKey);
अब हमारे पास एक स्थिर साइट है। पूर्ण fingerprint.js स्रोत अधिकतर स्पष्ट से अनुकूलित
संकेत प्रकार और वजन
विभिन्न क्रियाओं में भिन्न अभिप्राय स्तर हैं आधार भार.
संकेत प्रकार: वज़न श्रेणियाँ
// Mostlylucid.SegmentCommerce/Data/Entities/Profiles/SignalEntity.cs
public static class SignalTypes
{
// Passive signals (low intent)
public const string PageView = "page_view"; // 0.01
public const string CategoryBrowse = "category_browse"; // 0.03
public const string ProductImpression = "product_impression"; // 0.02
// Active signals (medium intent)
public const string ProductView = "product_view"; // 0.10
public const string ProductClick = "product_click"; // 0.08
public const string Search = "search"; // 0.05
// High-intent signals
public const string AddToCart = "add_to_cart"; // 0.35
public const string AddToWishlist = "add_to_wishlist"; // 0.25
public const string ViewCart = "view_cart"; // 0.15
public const string BeginCheckout = "begin_checkout"; // 0.40
// Conversion signals (highest intent)
public const string Purchase = "purchase"; // 1.00
public const string Review = "review"; // 0.60
public const string Share = "share"; // 0.50
public static readonly Dictionary<string, double> BaseWeights = new()
{
{ PageView, 0.01 },
{ ProductView, 0.10 },
{ AddToCart, 0.35 },
{ Purchase, 1.00 },
// ... (see full code for complete list)
};
public static double GetBaseWeight(string signalType)
{
return BaseWeights.GetValueOrDefault(signalType, 0.05);
}
}
यह क्यों महत्वपूर्ण है
- एकल पृष्ठ दृश्य (
0.01) wonM SK1सिग्नल पर प्रभाव नहीं डालता - गाड़ी में जोड़ना (
0.35) एक मजबूत अभिप्राय संकेत है - खरीदें (
1.00) सबसे मजबूत संकेत है
इस पदानुक्रम से "drive-by ब्राउजिंग द्वारा प्रोफ़ाइल को प्रदूषित करने से रोका जाता है
SessionCollector: रिकार्डिंग सिग्नल (Cache
// Mostlylucid.SegmentCommerce/Services/Profiles/SessionCollector.cs
public async Task<SessionProfile> RecordSignalAsync(
SessionSignalInput input, CancellationToken ct = default)
{
var sessionKey = input.SessionKey;
// Get or create session FROM CACHE (never DB)
var session = _cache.Get<SessionProfile>(sessionKey);
if (session == null)
{
session = new SessionProfile
{
SessionKey = sessionKey,
StartedAt = DateTime.UtcNow
};
}
session.LastActivityAt = DateTime.UtcNow;
var weight = input.Weight ?? SignalTypes.GetBaseWeight(input.SignalType);
// Update in-memory aggregates
session.TotalWeight += weight;
session.SignalCount++;
if (!string.IsNullOrEmpty(input.Category))
{
session.Interests.TryGetValue(input.Category, out var currentScore);
session.Interests[input.Category] = currentScore + weight;
}
if (input.SignalType == SignalTypes.AddToCart)
{
session.CartAdds++;
}
// Put back in cache with sliding expiration
_cache.Set(sessionKey, session, new MemoryCacheEntryOptions
{
SlidingExpiration = TimeSpan.FromMinutes(30),
Priority = CacheItemPriority.Normal,
PostEvictionCallbacks = { /* elevation callback */ }
});
return session;
}
तेजी से क्योंकि
- मेमोरी में शुद्ध
- कोई सीरियलाइजेशन ओवरहेड नहीं है (IMemoryCache
- कोई नेटवर्क कॉल नहीं
स्थायी प्रोफाइलें: उत्तेजित संकेत
जब एक सत्र उच्च अभिप्राय दिखाता है (cart जोड़ता है स्थायी प्रोफ़ाइल.
PersistentProfileEntity: The Long-Term Profile
// Mostlylucid.SegmentCommerce/Data/Entities/Profiles/PersistentProfileEntity.cs
[Table("persistent_profiles")]
public class PersistentProfileEntity
{
[Key]
public Guid Id { get; set; } = Guid.NewGuid();
[Required]
[MaxLength(256)]
public string ProfileKey { get; set; } = string.Empty;
// How this profile is identified (Fingerprint, Cookie, Identity)
public ProfileIdentificationMode IdentificationMode { get; set; }
// Behavioral data (all JSONB)
[Column("interests", TypeName = "jsonb")]
public Dictionary<string, double> Interests { get; set; } = new();
[Column("affinities", TypeName = "jsonb")]
public Dictionary<string, double> Affinities { get; set; } = new();
[Column("brand_affinities", TypeName = "jsonb")]
public Dictionary<string, double> BrandAffinities { get; set; } = new();
[Column("price_preferences", TypeName = "jsonb")]
public PricePreferences? PricePreferences { get; set; }
[Column("traits", TypeName = "jsonb")]
public Dictionary<string, bool> Traits { get; set; } = new();
// Computed segments
public ProfileSegments Segments { get; set; } = ProfileSegments.None;
[Column("llm_segments", TypeName = "jsonb")]
public Dictionary<string, double>? LlmSegments { get; set; }
// Vector embedding for similarity matching
[Column("embedding", TypeName = "vector(384)")]
public Vector? Embedding { get; set; }
// Statistics
public int TotalSessions { get; set; }
public int TotalSignals { get; set; }
public int TotalPurchases { get; set; }
public int TotalCartAdds { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime LastSeenAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}
अभी भी शून्य पीआई:
ProfileKeyएक HMAC हैश है (परिवर्तनीय नहीं हैIdentificationModeहमें बताता है कि यह कैसे पहचाना गया था- सभी डाटा है व्यवहार संकेत, व्यक्तिगत जानकारी नहीं
सत्र → प्रोफ़ाइल
public async Task ElevateToProfileAsync(
SessionProfileEntity session,
PersistentProfileEntity profile,
CancellationToken ct = default)
{
if (session.IsElevated)
return;
// Merge interests (use higher value)
foreach (var (category, score) in session.Interests)
{
if (!profile.Interests.ContainsKey(category) ||
profile.Interests[category] < score)
{
profile.Interests[category] = score;
}
}
// Update stats
profile.TotalSessions++;
profile.TotalSignals += session.SignalCount;
profile.TotalCartAdds += session.CartAdds;
profile.LastSeenAt = DateTime.UtcNow;
profile.UpdatedAt = DateTime.UtcNow;
// Mark session as elevated
session.IsElevated = true;
session.PersistentProfileId = profile.Id;
// Clear segment cache (will be recomputed)
profile.SegmentsComputedAt = null;
profile.EmbeddingComputedAt = null;
await _db.SaveChangesAsync(ct);
}
जब उत्थान होता है
- गाड़ी के बाद जोड़ें (high intent
- खरीदने के बाद (परिवर्तन
- जब उपयोक्ता स्थायीता में विकल्प करता है
खंड परिभाषाएँ: प्रतिफल
हम दो भागों के लिए segments teased ' हैं,. अब चलो ' deliver क्रियाशील आउटपुट उन सभी संकेत संग्रह के - वे जवाब देते हैं "किसी तरह की खरीदार है यह है
क्यों फज्जी सदस्यता
पारंपरिक विखंडन द्विआधारी है
flowchart LR
subgraph "Binary Segmentation"
Profile1[3 purchases] -->|"Threshold: 5"| Out[NOT High-Value]
Profile2[5 purchases] -->|"Threshold: 5"| In[High-Value]
end
क्रय करने वाले ग्राहक को 4 के साथ समान रूप से व्यवहार किया जाता है
अस्पष्ट विखंडन प्रत्येक प्रोफ़ाइल को एक स्कोर देता है (0-1):
| खरीदें | द्विआधारी |
|---|---|
| 0 ≥ | नहीं |
| 2 ≥ | नहीं |
| 4 ≥ | नहीं |
अब आप अनुपातिक रूप से personalize कर सकते हैं
खण्ड परिभाषा संरचना
// Mostlylucid.SegmentCommerce/Services/Segments/SegmentDefinition.cs
public class SegmentDefinition
{
public string Id { get; set; } // "tech-enthusiast"
public string Name { get; set; } // "Tech Enthusiasts"
public string Description { get; set; } // "Users with strong interest in technology"
public string Icon { get; set; } // "🔧"
public string Color { get; set; } // "#3b82f6"
public List<SegmentRule> Rules { get; set; } = [];
// How rules combine: All (AND), Any (OR), Weighted (sum)
public RuleCombination Combination { get; set; } = RuleCombination.Weighted;
// Minimum score to be "a member" (0-1)
public double MembershipThreshold { get; set; } = 0.3;
public List<string> Tags { get; set; } = []; // For filtering/grouping
}
नियम प्रकार: क्या आप जाँच सकते हैं
प्रत्येक नियम प्रोफ़ाइल के एक आयाम का मूल्यांकन करता है
public enum RuleType
{
CategoryInterest, // Check interests.tech, interests.fashion, etc.
BrandAffinity, // Check brandAffinities.Sony, brandAffinities.Nike, etc.
PriceRange, // Check price preferences (budget vs luxury)
Trait, // Check boolean traits (prefersDeals, browsesExtensively)
Statistic, // Check totalPurchases, totalSessions, totalCartAdds
TagAffinity, // Check affinities.gadgets, affinities.organic, etc.
Recency, // Check days since last activity
Expression // Custom expressions (advanced)
}
नियम ऑपरेटर
public enum RuleOperator
{
GreaterThan, // value > threshold
GreaterOrEqual, // value >= threshold
LessThan, // value < threshold
LessOrEqual, // value <= threshold
Equal, // value == threshold
NotEqual, // value != threshold
Contains, // for array/string checks
Between, // for ranges
In, NotIn // for set membership
}
नियम संयोजन विधि
कैसे कई नियमों को अंतिम अंक में सम्मिलित किया जाता है
public enum RuleCombination
{
All, // AND logic: Score = min(all rule scores). All rules must pass.
Any, // OR logic: Score = max(all rule scores). Any rule can pass.
Weighted // Weighted sum: Score = Σ(rule.weight × rule.score) / Σ(rule.weight)
}
भारित सबसे आम है
वास्तविक खण्ड उदाहरण
यहाँ नमूना परियोजना में डिफ़ॉल्ट खंड हैं
1. तकनीकी उत्साही
new SegmentDefinition
{
Id = "tech-enthusiast",
Name = "Tech Enthusiasts",
Description = "Users with strong interest in technology products",
Icon = "🔧",
Color = "#3b82f6",
MembershipThreshold = 0.35,
Rules =
[
new() {
Type = RuleType.CategoryInterest,
Field = "interests.tech",
Operator = RuleOperator.GreaterOrEqual,
Value = 0.4,
Weight = 0.6, // 60% of score
Description = "Tech interest > 40%"
},
new() {
Type = RuleType.TagAffinity,
Field = "affinities.gadgets",
Operator = RuleOperator.GreaterOrEqual,
Value = 0.2,
Weight = 0.2, // 20% of score
Description = "Likes gadgets"
},
new() {
Type = RuleType.TagAffinity,
Field = "affinities.electronics",
Operator = RuleOperator.GreaterOrEqual,
Value = 0.2,
Weight = 0.2, // 20% of score
Description = "Likes electronics"
}
]
}
मूल्यांकन उदाहरण
- प्रोफ़ाइल है
interests.tech = 0.72,affinities.gadgets = 0.31,affinities.electronics = 0.15 - नियम
- नियम
- नियम
- अंतिम 0.95
- थ्रेसहोल्ड 95% विश्वास के साथ सदस्य
2. Cart Abandoners
new SegmentDefinition
{
Id = "cart-abandoner",
Name = "Cart Abandoners",
Description = "Users who add items to cart but don't complete purchase",
Icon = "🛒",
Color = "#ef4444",
MembershipThreshold = 0.4,
Rules =
[
new() {
Type = RuleType.Statistic,
Field = "totalCartAdds",
Operator = RuleOperator.GreaterOrEqual,
Value = 3,
Weight = 0.5,
Description = "3+ cart adds"
},
new() {
Type = RuleType.Statistic,
Field = "totalPurchases",
Operator = RuleOperator.LessThan,
Value = 2,
Weight = 0.5,
Description = "Few purchases"
}
]
}
यह पकड़ता है "カート में डाला जाता है लेकिन नहीं खरीदता है
3. उच्च
new SegmentDefinition
{
Id = "high-value",
Name = "High-Value Customers",
Description = "Customers who make frequent purchases and spend above average",
Icon = "💎",
Color = "#8b5cf6",
MembershipThreshold = 0.4,
Rules =
[
new() {
Type = RuleType.Statistic,
Field = "totalPurchases",
Operator = RuleOperator.GreaterOrEqual,
Value = 3,
Weight = 0.4,
Description = "3+ purchases"
},
new() {
Type = RuleType.PriceRange,
Field = "priceRange",
Value = "100-10000", // High-end shoppers
Weight = 0.3,
Description = "High price range"
},
new() {
Type = RuleType.Recency,
Field = "lastSeen",
Operator = RuleOperator.LessThan,
Value = 30,
Weight = 0.3,
Description = "Active in last 30 days"
}
]
}
4. सौदा Hunters
new SegmentDefinition
{
Id = "bargain-hunter",
Name = "Bargain Hunters",
Description = "Price-sensitive shoppers who love deals and discounts",
Icon = "🏷️",
Color = "#22c55e",
MembershipThreshold = 0.3,
Rules =
[
new() {
Type = RuleType.PriceRange,
Field = "priceRange",
Value = "0-75", // Budget shoppers
Weight = 0.5,
Description = "Low price preference"
},
new() {
Type = RuleType.Trait,
Field = "traits.prefersDeals",
Value = true,
Weight = 0.3,
Description = "Prefers deals"
},
new() {
Type = RuleType.Statistic,
Field = "totalCartAdds",
Operator = RuleOperator.GreaterThan,
Value = 5,
Weight = 0.2,
Description = "Shops around"
}
]
}
सभी डिफ़ॉल्ट खण्ड
नमून में सामान्य ई-commerce पैटर्नों को शामिल करने के लिए 10 खंड शामिल हैं
| खंड | | | चिह्न || | कुंजी नियम |---------|------|-----------|----------| उच्च|-Value ग्राहक |💎|3+ purchases,High spending, Recent |VIP treatment,Loyalty programs प्रौद्योगिकी उत्साही | फैशन आगे बढ़ने के लिए बारैन हन्टर्स | नई आगंतुकों | | | |👋 | МSK3 | {\displaystyle \mathcal {MSC सत्र | & quot; ,& quot, कोई क्रय नहीं करता है & #44; | Cart Abandoners cart adds, few purchases | Recovery emails Home Enthusiasts | | फिलिटीन सक्रिय निष्ठावान ग्राहक अनुसंधानकर्ता
segmentservice: कंप्यूटिंग सदस्यता
SegmentService सभी वर्ग नियमों के साथ प्रोफाइलों का मूल्यांकन करता है
// Mostlylucid.SegmentCommerce/Services/Segments/SegmentService.cs
public SegmentMembership EvaluateSegment(ProfileData profile, SegmentDefinition segment)
{
var ruleScores = new List<RuleScore>();
foreach (var rule in segment.Rules)
{
var (score, actualValue) = EvaluateRule(profile, rule);
ruleScores.Add(new RuleScore
{
RuleDescription = rule.Description,
Score = score,
Weight = rule.Weight,
ActualValue = actualValue // For transparency
});
}
// Combine based on segment's combination method
double finalScore = segment.Combination switch
{
RuleCombination.All => ruleScores.Min(r => r.Score),
RuleCombination.Any => ruleScores.Max(r => r.Score),
RuleCombination.Weighted => ComputeWeightedScore(ruleScores),
_ => 0
};
return new SegmentMembership
{
SegmentId = segment.Id,
SegmentName = segment.Name,
Score = Math.Round(finalScore, 3),
IsMember = finalScore >= segment.MembershipThreshold,
RuleScores = ruleScores,
Confidence = score switch // Human-readable
{
>= 0.8 => "Very High",
>= 0.6 => "High",
>= 0.4 => "Medium",
>= 0.2 => "Low",
_ => "Very Low"
}
};
}
स्पष्टीकरण बनाया गया
प्रत्येक सदस्यता परिणाम में शामिल है वास्तविक मूल्य जिसके परिणामस्वरूप प्राप्ताङ्क
// What the UI receives:
{
"segmentId": "tech-enthusiast",
"segmentName": "Tech Enthusiasts",
"score": 0.95,
"isMember": true,
"confidence": "Very High",
"ruleScores": [
{ "description": "Tech interest > 40%", "score": 1.0, "actualValue": "0.72" },
{ "description": "Likes gadgets", "score": 1.0, "actualValue": "0.31" },
{ "description": "Likes electronics", "score": 0.75, "actualValue": "0.15" }
]
}
उपयोगकर्ताओं को ठीक देखो क्यों एक खंड में रहे हैं।
सिग्नल प्रवाह
यहाँ यह है कि कैसे एक उत्पाद दृश्य सेगमेंट सदस्यता बन जाता है
sequenceDiagram
participant Browser
participant Cache as SessionCache
participant Outbox as Outbox
participant Segment as SegmentService
Browser->>Cache: Product view (category: "tech")
Cache->>Cache: Update in-memory session
Note over Cache: interests.tech += 0.10
Browser->>Cache: Add to cart (high intent)
Cache->>Outbox: Publish elevation event
Outbox->>Outbox: Write to outbox table
Note over Outbox: Background worker processes
Outbox->>Segment: Elevate to PersistentProfile
Segment->>Segment: Evaluate segment rules
Note over Segment: interests.tech: 0.72 >= 0.40 ✓<br/>Score: 0.95, IsMember: true
Segment-->>Browser: Segment memberships + explanations
आउटबॉक्स पैटर्न
सभी महत्वपूर्ण कार्यों के माध्यम से प्रवाह आउटबॉक्स पैटर्न-our primary orchestration mechanism
flowchart LR
Action[Cart Add] --> TX[Single Transaction]
TX --> DB[(Save + Outbox)]
DB --> Worker[Background Worker]
Worker --> Route[Route to Handlers]
style TX stroke:#2f9e44,stroke-width:3px
क्यों व्यापार डेटा और घटनाओं को एक एकल लेन-देन में लिखा जाता है
// Every action publishes to outbox in the same transaction
await using var transaction = await _db.Database.BeginTransactionAsync(ct);
cart.Items.Add(new CartItem { ProductId = productId });
await _db.SaveChangesAsync(ct);
_outbox.Publish(OutboxEventTypes.ProductAddedToCart, new { ProductId = productId });
await _db.SaveChangesAsync(ct);
await transaction.CommitAsync(ct);
// Event is now guaranteed to be processed
भाग 3 पूर्ण आउटबॉक्स क्रियान्वयन को कवर करता है
क्या है
इस भाग को शामिल किया गया
- Zero-PII प्रोफ़ाइल वास्तुकला (अस्थिर सत्रों के विपरीत स्थायी प्रोफाइलें
- खण्ड परिभाषाएँ अस्पष्ट सदस्यता और भारित नियमों के साथ
- खण्ड सेवा निर्मित
-के साथ स्पष्टीकरण
भाग 3 में गहराई ले जाता है
- आउटबॉक्स पैटर्न कार्यान्वयन - विश्वसनीय घटना प्रकाशन और एकल राउटर
- कार्य कतार PostgreSQL के साथ
SKIP LOCKEDवितरित संसाधन के लिए - सुनें त्वरित नौकरी लेने के लिए (नहीं मतदान
- यूआई और पारदर्शिता - your interests" dashboard and segment explorer
खंड इस प्रणाली के क्रियाशील आउटपुट हैं।