-
Notifications
You must be signed in to change notification settings - Fork 2
/
SocialTrendingGauge.cs
153 lines (128 loc) · 5.17 KB
/
SocialTrendingGauge.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NFX.Instrumentation;
using NFX.Serialization.BSON;
using NFX.DataAccess.Distributed;
using NFX;
namespace Agni.Social.Trending
{
/// <summary>
/// Advances entity trending by the specified count of events
/// </summary>
[Serializable]
[BSONSerializable("BAC4E8C4-9ED2-49C4-A95D-17B6A402FA7E")]
public sealed class SocialTrendingGauge : LongGauge, ISocialLogic
{
public const string BSON_FLD_ENTITY = "ent";
public const string BSON_FLD_G_SHARD = "g_s";
public const string BSON_FLD_G_ENTITY = "g_e";
public const string BSON_FLD_DIMS = "dims";
public const int MAX_ENTITY_NAME_LENGTH = 8;
public const int MAX_DIMENSION_LENGTH = 500;
public static bool TryValidateEntityName(string entityName)
{
if (entityName.IsNullOrWhiteSpace()) return false;
if (entityName.Length > MAX_ENTITY_NAME_LENGTH) return false;
for (var i = 0; i < entityName.Length; i++)
{
var c = entityName[i];
if ((c < 'A' || c > 'Z') &&
(c < 'a' || c > 'z') &&
(c < '0' || c > '9' || i == 0) &&
(c != '_'))
return false;
}
return true;
}
/// <summary>
/// Records the trending information.
/// </summary>
/// <param name="tEntity">Entity type - what is trending</param>
/// <param name="gShard">Sharding area key</param>
/// <param name="gEntity">GDID of the trending entity</param>
/// <param name="count">Trending count</param>
/// <param name="dimensions">Dimensions vector in plain or laconic format</param>
public static void Emit(string tEntity, GDID gShard, GDID gEntity, long count, string dimensions)
{
if (!TryValidateEntityName(tEntity))
throw new SocialException(StringConsts.ARGUMENT_ERROR + "Emit(tEntity!Valid:'{0}')".Args(tEntity));
if (dimensions != null && dimensions.Length > MAX_DIMENSION_LENGTH)
throw new SocialException(StringConsts.ARGUMENT_ERROR + "Emit(dims to long)");
var inst = App.Instrumentation;
if (!inst.Enabled) return;
var datum = new SocialTrendingGauge(count)
{
m_Entity = tEntity,
m_G_Shard = gShard,
m_G_Entity = gEntity,
m_Dimensions = dimensions
};
inst.Record(datum);
}
private SocialTrendingGauge(long count) : base(null, count)
{
}
private string m_Entity;
private GDID m_G_Shard;
private GDID m_G_Entity;
private string m_Dimensions;
public override string Source
{
get
{
var sb = new StringBuilder(128);
sb.Append(m_Entity); sb.Append('|');
sb.Append(m_G_Shard); sb.Append('|');
sb.Append(m_G_Entity); sb.Append('|');
sb.Append(m_Dimensions);
return sb.ToString();
}
}
/// <summary> Returns entity type </summary>
public string Entity { get { return m_Entity;} }
/// <summary> Returns entity sharding key </summary>
public GDID G_Shard { get { return m_G_Shard;} }
/// <summary> Returns entity GDID </summary>
public GDID G_Entity { get { return m_G_Entity;} }
/// <summary>
/// Dimensions used for classification. e.g. 'USA', 'Accounting' etc.
/// Use laconic to assign multiple.
/// ATTENTION! Making dimensions too detailed significantly increases the number of samples
/// that the system needs to process in real time.
/// ATTENTION! In a particular business system, if dimension is a vector, it must be an ordered tuple of attr/values of the fixed size
/// (e.g "category,class" and "class,category" are different dimensions)
/// </summary>
public string Dimensions { get { return m_Dimensions;} }
public override string Description { get { return "Advances '{0}' social trending by the specified count of events".Args(Entity);}}
public override string ValueUnitName { get { return CoreConsts.UNIT_NAME_EVENT; }}
protected override Datum MakeAggregateInstance()
{
var aggregated = new SocialTrendingGauge(this.Value)
{
m_Entity = this.m_Entity,
m_G_Shard = this.m_G_Shard,
m_G_Entity = this.m_G_Entity,
m_Dimensions = this.m_Dimensions
};
return aggregated;
}
public override void SerializeToBSON(BSONSerializer serializer, BSONDocument doc, IBSONSerializable parent, ref object context)
{
base.SerializeToBSON(serializer, doc, parent, ref context);
doc.Add(BSON_FLD_ENTITY, m_Entity);
doc.Add(BSON_FLD_G_SHARD, m_G_Shard.ToString());
doc.Add(BSON_FLD_G_ENTITY, m_G_Entity.ToString());
doc.Add(BSON_FLD_DIMS, m_Dimensions);
}
public override void DeserializeFromBSON(BSONSerializer serializer, BSONDocument doc, ref object context)
{
base.DeserializeFromBSON(serializer, doc, ref context);
m_Entity = doc.TryGetObjectValueOf(BSON_FLD_ENTITY) .AsString();
m_G_Shard = doc.TryGetObjectValueOf(BSON_FLD_G_SHARD) .AsGDID ();
m_G_Entity = doc.TryGetObjectValueOf(BSON_FLD_G_ENTITY) .AsGDID ();
m_Dimensions = doc.TryGetObjectValueOf(BSON_FLD_DIMS) .AsString();
}
}
}