我现在正在寻找很长时间来解决我的问题,但几乎没有发现任何有用的东西。 希望你们中的一些人可以给我一个提示。
我有一个关系A,格式如下:username,timestamp,ip
例如:
Harald 2014-02-18T16:14:49.503Z 123.123.123.123
Harald 2014-02-18T16:14:51.503Z 123.123.123.123
Harald 2014-02-18T16:14:55.503Z 321.321.321.321
我想知道,谁在不到5秒内改变了他的ip地址。所以第二行和第三行应该很有趣。
我想按用户名对关系进行分组,并希望将实际行的时间戳与下一行进行比较。如果ip地址不相同且时间戳小于5秒,则应该在输出处。
有人可以帮我解决这个问题吗?
问候。
首先,我想感谢你的时间。
但我实际上停留在Sessionize部分。
这是我的数据:
aoebcu 2014-02-19T14:23:17.503Z 220.61.65.25
aoebcu 2014-02-19T14:23:14.503Z 222.117.144.19
aoebcu 2014-02-19T14:23:14.503Z 222.117.144.19
jekgru 2014-02-19T14:23:14.503Z 213.56.157.109
zmembx 2014-02-19T14:23:12.503Z 199.188.198.91
qhixcg 2014-02-19T14:23:11.503Z 203.40.104.119
我的代码到现在为止如下:
hijack_Reduced = FOREACH finalLogs GENERATE ClientUserName, timestamp, OriginalClientIP;
hijack_Filtered = FILTER hijack_Reduced BY OriginalClientIP != '-';
hijack_Sessionized = FOREACH (GROUP hijack_Filtered BY ClientUserName) {
views = ORDER hijack_Filtered BY timestamp;
GENERATE FLATTEN(Sessionize(views)) AS (ClientUserName,timestamp,OriginalClientIP,session_id);
}
但是当我运行此脚本时,我收到以下错误消息:
15:36:22错误 - org.apache.pig.tools.pigstats.SimplePigStats.setBackendException(542) |错误0:执行[POUserFunc时的异常(名称: POUserFunc(datafu.pig.sessions.Sessionize)[bag] - scope-199运算符 密钥:scope-199)children:[]时为null: java.lang.IllegalArgumentException:格式无效:“aoebcu”
我已经尝试了很多,但没有任何效果。 你知道吗?
此致
答案 0 :(得分:1)
虽然您可以为此编写UDF,但您实际上可以使用Apache DataFu中已有的UDF来解决此问题。
我的解决方案涉及将会话应用于数据。基本上,您查看连续事件并为每个事件分配会话ID。如果两个事件之间经过的时间超过指定的时间,在您的情况下为5秒,则下一个事件将获得新的会话ID。否则连续事件将获得相同的会话ID。一旦为每个事件分配了其会话ID,其余部分就很容易。我们按会话ID分组,并查找具有多个不同IP地址的会话。
我将完成我的解决方案。
假设您有以下输入数据。 Harold和Kumar都改变了他们的IP地址。但哈罗德在5秒内完成,而库马尔没有。因此,我们脚本的输出应该只是“Harold”。
Harold,2014-02-18T16:14:49.503Z,123.123.123.123
Harold,2014-02-18T16:14:51.503Z,123.123.123.123
Harold,2014-02-18T16:14:55.503Z,321.321.321.321
Kumar,2014-02-18T16:14:49.503Z,123.123.123.123
Kumar,2014-02-18T16:14:55.503Z,123.123.123.123
Kumar,2014-02-18T16:15:05.503Z,321.321.321.321
加载数据
data = LOAD 'input' using PigStorage(',')
AS (user:chararray,time:chararray,ip:chararray);
现在从DataFu定义几个UDF。如前所述,Sessionize UDF执行会话。 DistinctBy UDF将用于在每个会话中查找不同的IP地址。
define Sessionize datafu.pig.sessions.Sessionize('5s');
define DistinctBy datafu.pig.bags.DistinctBy('1');
按用户对数据进行分组,按时间排序,并应用Sessonize UDF。请注意,时间戳必须是第一个字段,因为这是Sessionize期望的。此UDF将会话ID附加到每个元组。
data = FOREACH data GENERATE time,user,ip;
data_sessionized = FOREACH (GROUP data BY user) {
views = ORDER data BY time;
GENERATE flatten(Sessionize(views)) as (time,user,ip,session_id);
}
现在数据已经过会话,我们可以按用户和会话进行分组。我也按用户分组,因为我想把这个值吐出来。我们将一系列事件传递给DistinctBy UDF。有关更详细的说明,请查看此UDF的文档。但基本上我们会得到尽可能多的元组,因为每个会话都有不同的IP地址。请注意,我已从以下关系中删除了时间。这是因为1)不需要它,2)当处理包含短划线的字段时,DataFu的1.2.0中的DistinctBy有一个错误,就像时间字段那样。
data_sessionized = FOREACH data_sessionized GENERATE user,ip,session_id;
data_sessionized = FOREACH (GROUP data_sessionized BY (user, session_id)) GENERATE
group.user as user,
SIZE(DistinctBy(data_sessionized)) as distinctIpCount;
现在选择具有多个不同IP地址的所有会话,并为这些会话返回不同的用户。
data_sessionized = FILTER data_sessionized BY distinctIpCount > 1;
data_sessionized = FOREACH data_sessionized GENERATE user;
data_sessionized = DISTINCT data_sessionized;
这简单地产生:
Harold
以下是完整的源代码,您应该能够直接粘贴到DataFu单元测试并运行:
/**
define Sessionize datafu.pig.sessions.Sessionize('5s');
define DistinctBy datafu.pig.bags.DistinctBy('1'); -- distinct by ip
data = LOAD 'input' using PigStorage(',') AS (user:chararray,time:chararray,ip:chararray);
data = FOREACH data GENERATE time,user,ip;
data_sessionized = FOREACH (GROUP data BY user) {
views = ORDER data BY time;
GENERATE flatten(Sessionize(views)) as (time,user,ip,session_id);
}
data_sessionized = FOREACH data_sessionized GENERATE user,ip,session_id;
data_sessionized = FOREACH (GROUP data_sessionized BY (user, session_id)) GENERATE
group.user as user,
SIZE(DistinctBy(data_sessionized)) as distinctIpCount;
data_sessionized = FILTER data_sessionized BY distinctIpCount > 1;
data_sessionized = FOREACH data_sessionized GENERATE user;
data_sessionized = DISTINCT data_sessionized;
STORE data_sessionized INTO 'output';
*/
@Multiline private String sessionizeUserIpTest;
private String[] sessionizeUserIpTestData = new String[] {
"Harold,2014-02-18T16:14:49.503Z,123.123.123.123",
"Harold,2014-02-18T16:14:51.503Z,123.123.123.123",
"Harold,2014-02-18T16:14:55.503Z,321.321.321.321",
"Kumar,2014-02-18T16:14:49.503Z,123.123.123.123",
"Kumar,2014-02-18T16:14:55.503Z,123.123.123.123",
"Kumar,2014-02-18T16:15:05.503Z,321.321.321.321"
};
@Test
public void sessionizeUserIpTest() throws Exception
{
PigTest test = createPigTestFromString(sessionizeUserIpTest);
this.writeLinesToFile("input",
sessionizeUserIpTestData);
List<Tuple> result = this.getLinesForAlias(test, "data_sessionized");
assertEquals(result.size(),1);
assertEquals(result.get(0).get(0),"Harold");
}