我认为 gawk 不一定能处理这 500mb,但你可以在大多数语言(java、perl 等)中完成同样的事情。我还假设仅列出边缘就可以了,无需将它们重新编译成一行。
我将假设一个像这样的输入文件(“input”)(其中 url 现在是名称):
joe;proj2,proj9,pro8
erin;proj1,proj7,pro8
sue;proj47,pro7
elmo;pro7
运行以下命令:
cat input | gawk -F"," '{
split( $1, arr, ";" );
printf( "%s;%s\n", arr[1], arr[2] );
for( i = 2; i <= NF; i++ ) { printf( "%s;%s\n", arr[1], $i ); }
}'
产生以下输出:
joe;proj2
joe;proj9
joe;pro8
erin;proj1
erin;proj7
erin;pro8
sue;proj47
sue;pro7
elmo;pro7
根据gephi csv 格式,这些似乎是边缘
或者您可以进一步处理输出。
我不记得 awk/gawk 是否预先消耗了整个文件。如果输出没问题,那么将每一行处理成多行将适用于许多其他语言。
好的 - 虽然我仍然认为我的第一次尝试更有用,但这是第二个版本,其中所有内容都被稍微重写并包括一个新的 gawk 来制作点文件有向图输出(这让我可以在 Yed 中查看它 - 见评论)。
“输入”文件,如(第一次尝试中的拼写错误在“proj”中删除了“j”):
joe;proj2,proj9,proj8
erin;proj1,proj7,proj8
sue;proj47,proj7
elmo;proj7
用以下内容制作一个可执行文件(我称之为“explode”):
gawk -F"," '
{
count = split( $1, sc, ";" );
printf( "%s %s\n", sc[2], sc[1] );
for( i = 2; i <= NF; i++ ) { printf( "%s %s\n", $i, sc[1] ); }
}
'
这会更改输出或原始 gawk,因为它将用于排序/提供下一个 gawk 脚本(另一个可执行文件;我称之为“组合”):
gawk -F" " '
BEGIN { printf( "digraph similar_users (\n" );
project_name = "";
users = "";
}
{
if( $1 ~ project_name )
build_users_string( $2 );
else {
make_user_nodes( users );
users = "";
build_users_string( $2 );
}
project_name = $1
}
function build_users_string( u )
{
users = sprintf( "%s%s%s", users, length( users ) == 0 ? "" : " ", u );
}
function make_user_nodes( u )
{
if( (count = split( u, arr, " " )) <= 1 )
return 1;
for( i = 1; i <= count; i++ )
{
printf( "%s -> ", arr[ i ] );
for( j = 1; j <= count; j++ )
if( j != i )
{
end = (i == count ) ? count-1 : count;
printf( "%s%s", arr[j], j != end ? "," : ";\n" );
}
}
return( count );
}
END { make_user_nodes( users );
printf( ")\n" );
}
'
它从“explode”脚本中读取排序后的输入文件,运行时如下:
cat input | explode | sort | combine > output.dot
生成文件“output.dot”,其中“user -> 与同一项目关联的用户列表”
digraph similar_users (
elmo -> erin,sue;
erin -> elmo,sue;
sue -> elmo,erin;
erin -> joe;
joe -> erin;
)
使用的内存应该只与最后一个脚本中的排序和最大的项目/用户转换一样糟糕,因为它只在项目名称更改时处理按项目分组的用户。更占用内存的“单程”会将所有用户放在 proj -> (用户列表)的地图中,并在最后完成地图的所有处理。请注意,指向单个项目的用户将被删除。