现状
我有一个桌面应用程序(C ++ Win32),我希望匿名跟踪用户的使用情况分析(操作,点击,使用时间等)
跟踪是通过指定的Web服务完成的,用于特定的操作(安装,卸载,点击),所有内容都由我的团队编写并存储在我们的数据库中。
需要
现在我们使用各种数据添加更多使用类型和事件,因此我们需要定义服务
我希望为所有使用类型提供单一通用服务,而不是为每个操作提供大量不同的Web服务,这些服务能够接收不同的数据类型。
例如:
问题
我正在寻找一个优雅的&存储这种不同数据的便捷方式,以后我可以轻松查询
我能想到的替代方案:
将每种使用类型的不同数据存储为JSON / XML对象的一个字段,但是为这些字段提取数据和编写查询非常困难
为每条记录提供额外的N个数据字段,但这似乎非常浪费。
对于这种模型的任何想法?也许像谷歌分析?请告知......
技术:数据库是在phpMyAdmin下运行的MySQL。
声明: 有一个similar post,它引起我注意DeskMetrics和Tracker bird等服务,或尝试将谷歌分析嵌入到C ++本机应用程序中,但我宁愿通过自己的服务,并更好地了解如何设计这种模型。
谢谢!
答案 0 :(得分:2)
这似乎是一个database normalization问题。
我还假设您还有一个名为events
的表,其中将存储所有事件。
此外,我假设您必须使用以下数据属性(为简单起见):window_name, source_id, user_action, index
要实现规范化,我们需要以下表格:
events
data_attributes
attribute_types
这就是每个表的结构:
mysql> describe events;
+------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| event_type | varchar(255) | YES | | NULL | |
+------------+------------------+------+-----+---------+----------------+
mysql> describe data_attributes;
+-----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| event_id | int(11) | YES | | NULL | |
| attribute_type | int(11) | YES | | NULL | |
| attribute_name | varchar(255) | YES | | NULL | |
| attribute_value | int(11) | YES | | NULL | |
+-----------------+------------------+------+-----+---------+----------------+
mysql> describe attribute_types;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| type | varchar(255) | YES | | NULL | |
+-------+------------------+------+-----+---------+----------------+
我们的想法是,您必须使用所有可能的类型填充attribute_types
。然后,对于每个新事件,您将在events
表中添加一个条目以及data_attributes
表中的相应条目,以将该事件映射到具有适当值的一个或多个属性类型。
示例:
"button_A_click" event, has data with 1 field: {window_name "Dummy Window Name"}
"show_notification" event, has data with 3 fields: {source_id: 99, user_action: 44, index: 78}
将表示为:
mysql> select * from attribute_types;
+----+-------------+
| id | type |
+----+-------------+
| 1 | window_name |
| 2 | source_id |
| 3 | user_action |
| 4 | index |
+----+-------------+
mysql> select * from events;
+----+-------------------+
| id | event_type |
+----+-------------------+
| 1 | button_A_click |
| 2 | show_notification |
+----+-------------------+
mysql> select * from data_attributes;
+----+----------+----------------+-------------------+-----------------+
| id | event_id | attribute_type | attribute_name | attribute_value |
+----+----------+----------------+-------------------+-----------------+
| 1 | 1 | 1 | Dummy Window Name | NULL |
| 2 | 2 | 2 | NULL | 99 |
| 3 | 2 | 3 | NULL | 44 |
| 4 | 2 | 4 | NULL | 78 |
+----+----------+----------------+-------------------+-----------------+
要为此数据编写查询,可以使用MySQL中的COALESCE函数为您获取值,而无需检查哪些列为NULL
。
这是我破解的一个简单示例:
SELECT events.event_type as `event_type`,
attribute_types.type as `attribute_type`,
COALESCE(data_attributes.attribute_name, data_attributes.attribute_value) as `value`
FROM data_attributes,
events,
attribute_types
WHERE data_attributes.event_id = events.id
AND data_attributes.attribute_type = attribute_types.id
产生以下输出:
+-------------------+----------------+-------------------+
| event_type | attribute_type | value |
+-------------------+----------------+-------------------+
| button_A_click | window_name | Dummy Window Name |
| show_notification | source_id | 99 |
| show_notification | user_action | 44 |
| show_notification | index | 78 |
+-------------------+----------------+-------------------+
答案 1 :(得分:1)
您可以定义与数组一起使用的自定义类/结构。然后序列化此数据并发送到WebService。例如:
[Serializable()]
public class ActionDefinition {
public string ID;
public ActionType Action; // define an Enum with possible actions
public List[] Fields; //Or a list of 'some class' if you need more complex fields
}
List AnalyticsCollection = new List(Of, Actiondefinition);
// ...
SendToWS(Serialize(AnalyticsCollection));
现在,您可以根据需要动态添加任意数量的事件,并具有所需的灵活性。
在服务器端,您只需解析数据:
List[of, ActionDefinition] AnalyticsCollection = Deserialize(GetWS());
foreach (ActionDefinition ad in AnalyticsCollection) {
switch (ad.Action) {
//.. check for each action type
}
}
我建议添加校验和等安全机制。我想de / serializer在C ++中是非常自定义的,所以也许简单的Base64编码可以做到这一点,它可以作为ascii文本传输。
答案 2 :(得分:0)
你可以为每个事件制作一个表格,你宣布什么是param意味着什么。然后你有一个主表,只输入事件名称和param1等。管理工具非常简单,你可以浏览所有事件,并使用声明每个事件的表来描述它们。例如。对于你的事件button_A_click你插入描述表:
Name Param1
button_A_Click WindowTitle
因此,您可以对活动进行分组或仅选择一个活动..
这就是我解决它的方法。