简化
许多图表大多是重复的。两个事件共享四十个 IP,每个 IP 需要一个节点、一个标签和两条边,尽管重要的是“这两个事件共享四十个 IP”。一个枢纽有几十个叶子,与其他地方没有联系。 Simplify 将扮演相同角色的节点折叠成一个 group,并在其位置绘制:
const options = {
render: {
nodeTypeAccessor: (node) => node.getData().type,
},
UI: {
simplify: {
rules: [{ kind: 'neighbours', minSize: 5 }],
},
},
}组是视图,而不是数据
graph.getNodes()、getEdges()、表、导出和撤消历史记录看到真实节点。每当图表发生变化时,就会根据它们重新计算一个组,并且不会保存任何内容。
查看它在 简化图表 卡上运行。
规则
UI.simplify.rules 是一个有序列表。每个规则给一些节点一个密钥,共享密钥的节点成为一组,只要至少有minSize个。
- 规则按照的顺序运行,每个规则都将其上面的规则所创建的组视为普通节点。因此,一个组可以通过稍后的规则再次分组。
- 规则在节点过滤器之后运行,因此组仅保留通过它们的内容:隐藏四十个IP中的三个,组读取37。边缘层不会更改组;关闭其中之一只会隐藏线条。
- 附有注释的节点和扩展集群是从不分组。封闭的集群与任何其他节点一样分组。
- 除非显示
enabled: false,否则声明的规则已启用。
没有UI.simplify,full模式提供在简化轨道模式下关闭的内置规则;其他模式什么都不运行。 UI.simplify.enabled: false 删除该功能。
邻居规则
{ kind: 'neighbours', minSize: 5, typeOf: (node) => node.getData().type }它折叠链接到 ** 的一种类型的节点,其方式与**相同:指向它们的相同节点以及它们指向的相同节点。轮毂的叶子是最简单的情况。由于事件 A 和 B 共享三个 TTP,并且每个 TTP 都有自己的两个,因此您将获得三个组:A 和 B 之间共享的三个 TTP,以及每侧两个。
- 类型是规则自己的
typeOf,否则为UI.simplify.typeOf,否则为render.nodeTypeAccessor。没有类型组的节点。 - 没有任何链接的节点永远不会被分组:一个组需要一些东西来挂起。
- 获得链接的节点离开其组,前往与其新邻居匹配的节点。如果剩余的数量少于
minSize,则该团体解散。 - 组在保留其大部分成员的同时保留其身份,因此具有相同邻居的新节点会加入现有组而不移动它。
链式法则
{ kind: 'chains', minSize: 5, typeOf: (node) => node.getData().type }它折叠悬挂在一个节点上的链条。包含三十个文件的事件,每个文件都有自己的哈希值,是三十个链file > sha256:文件不共享邻居,因为每个文件都链接自己的哈希值,因此邻居规则不会影响它们。链式法则将它们折叠成一组链接到一组散列的文件,并将它们之间的三十个链接绘制为一条线。
- 节点的tail是唯一链接来自该节点的节点,顺流而下,而每一步仅沿着链链接。一个节点与另外两个节点、一个分支或一个循环相连,链就在那里结束。
- 当引导相同形状的链时,当它们共享相同的其他链接和类型时,它们会折叠在一起。五个隔离对
domain → ip给出一组链接到一组 5 个 IP 的 5 个域。 - 每层的链条也会折叠:在他们的头组下,或者当没有匹配时在他们自己的头下。
- 链接计数仅下游:一个节点唯一指向另一个节点的链接不是该节点的尾部。
- 放置在邻居规则之后,它会折叠该规则留下的内容。邻居规则创建的组可以是尾部。
很少的环节和核心
{ kind: 'degree', minDegree: 2 }
{ kind: 'kcore', k: 2 }这些规则根据节点的链接程度将节点从画布中取出,并将它们折叠到它们悬挂的节点中,以便计数保留在画布上:
- 很少的链接 (
degree) 折叠少于minDegree链接的节点:在 2 处,集线器的叶子成为集线器上的一组。 - 在核心之外(
kcore)剥离少于k链接的节点,然后对剩下的再次执行此操作,直到每个站立的节点都具有k链接。当值为 2 时,它会折叠悬挂在图表上的整棵树,而不仅仅是它们的叶子。
接触相同节点的折叠节点共享一个组,无论其类型如何,并且一个组可以包含单个节点:它在其锚点上读取“1 more”。连接在一起的折叠节点进入同一组,因此悬挂在集线器上的路径会与集线器的叶子折叠。一连串没有接触到任何站立的折叠节点是它自己的一组,并且每个没有连接到任何东西的节点共享一个组。两个设置的范围都是从 1 到 10,并且链接都以任意方式计数。
在邻居规则之后,一组是这些规则的一个节点:它的链接就是它的线。一群孤立无援的人保持原样。
社区
{ kind: 'communities', level: 4 }对于对于上述规则而言太大的图,社区会折叠整个邻域:彼此链接比与图的其余部分更紧密地链接的节点成为一组,无论其类型如何。它们是用莱顿算法找到的,对于同一张图每次都是相同的。
level从1,细,许多小社区,到7,粗,少数大社区。在简化模式下,它是一个滑块,当您放开时应用。- 这些社区在工作人员中被发现,在页面之外,只有当图表的形状发生变化时才会再次出现。同时,卡片上写着分组…,并且之前的组保留。如果没有工作人员可以启动,例如内容安全策略会阻止 blob 工作人员,则相同的代码会在页面上运行;
useWorker: false要求这样做。 - 对于每条规则,一个节点的社区仍然是一个节点,而带注释的节点则不存在。
- 与其他内置规则不同,社区仅在声明时处于简化模式。
拓展着陆
{ kind: 'landings', minSize: 2 }以组形式摄取,在pivot查看窗格的页脚中,会将选定的行折叠起来:每种类型一个组,挂在您旋转的节点上。四十个 IP 以“40 × ip”形式到达,而不是四十个点。
- 一个组持有所摄取的添加的。画布上已有的节点将保留在原来的位置。
- 与邻居规则不同,成员保留以后链接到的任何内容。将其拉出、删除或撤消摄取以将其取出。撤消会解散该组,重做会将其恢复。
- 节点数少于
minSize(默认为 2)的类型将作为普通节点。 - 该规则首先运行,因此它之后的规则将每个着陆视为一个节点。您不需要声明它:第一个分组着陆将其添加到“简化”模式的顶部,打开。声明它以将其放在其他地方或更改其最小组。
- 哪些着陆被分组为会话的最后,如开放组。
- 登陆组的
landing名称来自于:{ runId, pivotId, pivotLabel },带有来自拓展定义的标签。芯片无需解析运行 ID 即可读取12 × ip · Event elements。
要对每个拓展结果进行分组,请设置 pivotIngestGrouped。一键运行和autoIngest拓展,永远不会打开评论,然后也进行分组:
new Pivotick(el, data, { pivotIngestGrouped: true })评论的页脚遵循以下选项:
pivotIngestGrouped | 摄取所选和摄取全部 | 第二个按钮 |
|---|---|---|
| 关闭(默认) | 土地松动 | 集体摄取 |
| 上 | 土地分组 | 松散摄取 |
当 UI.simplify 关闭时,该选项不会执行任何操作,也没有第二个按钮。
要从代码中选择一次摄取,请传递 group:
await graph.pivots.ingest('correlations', 'triage', { group: true })自定义规则
您自己的规则是 partition(view) 返回每个节点的密钥:
{
kind: 'custom',
id: 'bySensor',
label: 'By sensor', // its name in the Simplify mode
description: 'Sightings reported by the same sensor.',
minSize: 2, // the default for a custom rule
partition: (view) => new Map(view.nodes
.filter((node) => view.typeOf(node) === 'sighting')
.map((node) => [node.id, node.getData().sensor])),
}view 是这条规则所看到的图形:
| 会员 | 它是什么 |
|---|---|
nodes | 此规则可能分组的节点:通过过滤器的节点,用早期规则的组代替其成员。带注释的节点、拉出的节点和扩展的簇都被省略。 |
inNeighbours(node) / outNeighbours(node) | 绘制的节点带有一条通往或来自该节点的线。 |
typeOf(node) | 规则分组的类型:UI.simplify.typeOf,否则render.nodeTypeAccessor。 |
groupOf(node) | 节点后面的组(当它是较早制定的规则时)。 |
地图之外的节点将保留其自身,并且不在 view.nodes 中的 id 将被忽略。抛出的规则被关闭,其处于简化模式的卡如此说明,并且其他规则仍然运行。
简化模式
导轨上的 Simplify 按钮会为每个规则打开一张卡片,按运行顺序排列:开关、其设置以及规则折叠的内容。该设置是用于最小组、最少链接或核心强度的 - / + 步进器,以及用于社区级别的滑块。应用程序声明的规则带有 app 标签。顶部的摘要读取画布上有多少个节点通过了过滤器,并且轨道按钮在任何规则折叠时对组进行计数。
与团队合作
一个组被绘制为一个节点,并且只要有明确的地方,它就为其成员起作用。
- 双击打开,Enter,侧边栏或上下文菜单。它的成员以普通节点的身份回归,在团体颜色的洗礼中,轻轻一拉就能将他们聚集在一起。拖动它们上方的筹码即可将它们全部移动;它的×将它们折叠起来。它的工具提示命名了创建该组的规则。成员们回到他们坐的地方;那些没有自己自由位置的人散布在群体周围,而现场物理会受到温和的推动,就像集群一样。
simulation.fitViewOnExpandCollapse适合打开和关闭时的视图。成员数量超过UI.simplify.openConfirmAbove(100) 的小组首先提出请求。 - 选择即可在侧边栏中的可排序列表中查看其成员。 拉出将成员保留在组之外,直到将其从其上下文菜单放回:在组打开时在画布上,或者从数据停靠中的行(无论组是否打开)放回。通过选择,它会提取出每个选定的成员。
- 在侧边栏或上下文菜单中的表中查看列出了数据坞中的成员,其中列过滤器进一步缩小了范围。桌子上方的芯片再次列出了每个节点。
- 选择成员、透视和删除作用于成员。 Pivot 和Delete 会经历通常的钩子,因此
onBeforeDelete会看到真实的节点。隐藏、删除和旋转所选内容,使组也对其成员起作用。 - 选择一个组会点亮它链接到的节点,就像选择一个节点会点亮其邻居一样。组不提供编辑和连接:它没有自己的数据。
打开组和拉出的节点将持续到会话中,并且不是撤消步骤。要恢复它们,请调用 graph.simplify.open() 和 pullOut()。
手工制作的组
选择两个或更多节点,然后在侧边栏批量栏中选择 Group 或在所选节点的上下文菜单中对所选节点进行 * 分组*。输入标题,或保留提供的标题(“3 × ip,2 × 域名”),所选内容将折叠到该标题下的一组中。
- 手工制作的组获胜。其规则手工制作先于其他规则运行,因此选中的节点会离开任何规则组。选定的组给出其成员,选择到第二个手工制作组的节点则离开第一个组。带注释的节点和开放簇不会出现,提示会显示有多少个。
- 它保留其成员链接到的任何内容。被删除或过滤掉的则不绘制;留下一名成员的小组根本不会被抽签,并且会带着其成员回来。
- 从侧边栏面板或其上下文菜单中重命名和取消组合。空标题再次按其类型对其进行标记。批量栏的取消分组删除选择保留或位于其中的每个手工制作的组。
- 分组、重命名和取消分组是撤消步骤,与打开或拉出不同。
- 它是视图状态:未导出,并且重新加载时消失。要保留它,请保存
getManualGroups()并将其交还给setManualGroups()。在new Graph()之后恢复、打开或拉出的组是开放布局的一部分:封闭的组被放置为一个点,开放的组的成员保持在一起。
const id = graph.simplify.groupNodes(['ip-1', 'ip-2', 'dom-7'], 'Suspicious infra')
graph.simplify.renameGroup(id, 'Cleared infra')
graph.simplify.ungroup(id)搜寻中
搜索会遍历每个节点,包括折叠的节点。
- 组内的匹配在其结果行中如此表示:in 12 × ip。
- 选择它会打开组并选择节点,就像 选择成员 一样。成员数量超过
openConfirmAbove的组将保持关闭状态并被选择。 - 在画布上显示全部,结果的最后一行或Shift+Enter,关闭搜索并点亮每个匹配项;其他一切都会消失。一群拿着火柴的人也被点亮,圆环上的主题颜色弧线显示了他们的份额。它的工具提示对它们进行了计数:2 / 12 匹配“198.51”。 Esc,单击空白画布或下一个搜索结束。
将图例条目悬停以相同的方式标记组:持有该条目节点的组被点亮,它们在其环上共享,因此混合类型的组不会读作全部。
具有自己搜索功能的应用程序可以使用 graph.simplify.setMatches(nodes, query) 以相同的方式标记其匹配项,并使用 setMatches([]) 清除它们。
外观
组是围绕圆盘的一个环,其类型的颜色与圆盘的颜色相同,一旦有空间,圆盘上就会显示计数,并且下面有一个标签。它随着数量的增加而增长,直至达到极限。一组混合类型有一个中性盘和一个按类型分开的环。
默认标签为12 × ip。 typeLabel 命名你的类型:
UI: {
simplify: {
typeLabel: (type, count) => `${count} ${count === 1 ? type : `${type}s`}`,
},
}render.groupStyle(group) 返回在默认值之上分层的 NodeStyle,因此 tiers、html、shape 和徽章在组上工作就像在节点上一样。 render.groupOutline(group) 设置开放组上的芯片的内容:
render: {
groupStyle: (group) => group.rule === 'bySensor' ? { color: '#6b7280' } : undefined,
groupOutline: (group) => `${group.members.length} from ${group.rule}`,
}groupStyle 还接收 base,即库绘制的样式。您返回的内容会替换其密钥,因此添加层的主机会扩展 base.tiers 以保留光盘上的计数:
render: {
groupStyle: (group, base) => ({
tiers: [...(base.tiers ?? []), { width: 140, height: 44, style: { html: () => chip(group) } }],
}),
}每个人都会收到一个GroupInfo:
| 领域 | 它是什么 |
|---|---|
id | 团体保持稳定,同时保留大部分成员。 |
rule | 'neighbours'、'chains'、'degree'、'kcore'、'communities'、'landings'、'manual' 或自定义规则的 id。 |
members | 它代表的真实节点。 |
typeCounts | 每种类型有多少成员; '' 不是类型。 |
anchors | 它链接到的绘制节点,包括组。 |
open | 其成员是否回到画布上。 |
level | 发现它的社区级别。 |
title | 手工制作组的标题。 |
landing | 登陆组的跑动和旋转:{ runId, pivotId, pivotLabel }。 |
组的工具提示为其规则命名,列出其链接到的内容,对于混合组,还按类型列出其成员。 tooltip.renderGroupExtra(group, ctx) 添加您自己的线,就像 renderNodeExtra 对于节点所做的那样。组会跳过为节点数据写入的tooltip.render和renderNodeExtra。
主机的类型和颜色
小组按 render.nodeTypeAccessor 计算其零件,并根据每个成员的风格颜色对它们进行着色。两个 UI.simplify 选项可以更改每个规则和组的设置,而无需触及样式、图例或过滤器:
typeOf(node)是每个规则分组所依据的类型,并且每个组都根据其部件进行计数:标签、混合环的份额、手工制作的组的标题。规则自己的typeOf仍然会赢得该规则。colorOf(node)是节点在组中代表的颜色:圆盘和环、开放式洗涤、工具提示的碎片。返回undefined会退回到节点的样式颜色。一个小组自己的groupStyle仍然对封闭的图纸有最后的决定权。
按元素设置样式、按子类型分组并自行绘制节点的主机:
const options = {
render: {
nodeTypeAccessor: (node) => node.getData().element,
nodeStyleMap: { attribute: { shape: 'none', html: drawAttribute } },
},
UI: {
simplify: {
typeOf: (node) => `${node.getData().element}:${node.getData().subtype}`,
colorOf: (node) => palette[node.getData().subtype],
},
},
}表中
数据坞列出了真实的节点。折叠节点在 Visibility 列中读取 grouped,并且 Group 列在存在组时为其命名。一条线绘制到一组的边也读取 grouped。
运行时
graph.simplify 保存规则和组:
| 方法 | 它的作用 |
|---|---|
setRules(rules) / getRules() | 更换规则;阅读每个人的状态以及折叠的内容。 |
setRuleEnabled(id, on) / setRuleSetting(id, n) | 简化模式的开关和步进器的作用。 setRuleMinSize(id, n) 仅设置最小组。 |
getGroups() / groupOf(node) | 每个组以及节点被折叠到的第一组。稍后规则再次折叠的组也会在持有该组的旁边列出,并且都列出其成员; summary().groups 计算画布绘制的封闭组。 |
open(group) / close(group) | 将小组成员放在画布上,或将其折叠起来。 |
pullOut(node) / putBack(node) / isPulledOut(node) | 将节点保留在任何组之外,或者将其放回。 |
groupNodes(nodes, title?) / renameGroup(group, title) / ungroup(groups) / isManual(group) | 手动制作、重新命名或删除组;每个都是撤消步骤。 |
getManualGroups() / setManualGroups(list) | 保存手工制作的组并恢复它们。 |
groupLanding(runId) / ungroupLanding(runId) / isLandingGrouped(runId) | 将拓展运行添加的内容折叠到着陆组中,或者再次将其松开。 |
summary() | 绘制多少个节点,通过过滤器,然后折叠。 |
setMatches(nodes, query) / matchesIn(group) | 在包含搜索的组上标记搜索的匹配项;读取一组拥有多少个。 |
onChange(listener) | 分组变化后调用;返回其取消订阅。 |