Pular para o conteúdo

Simplifique ​

Muitos gráficos são principalmente repetições. Dois eventos compartilham quarenta IPs, e cada IP custa um nó, um rótulo e duas arestas, embora o que importa é “esses dois eventos compartilham quarenta IPs”. Um hub tem dezenas de folhas que não se conectam a nenhum outro lugar. Simplify dobra nós que desempenham a mesma função em um group, desenhado em seu lugar:

ts
const options = {
    render: {
        nodeTypeAccessor: (node) => node.getData().type,
    },
    UI: {
        simplify: {
            rules: [{ kind: 'neighbours', minSize: 5 }],
        },
    },
}

Os grupos são uma visualização, não dados

graph.getNodes(), getEdges(), a tabela, as exportações e o histórico de desfazer veem os nós reais. Um grupo é recalculado a partir deles sempre que o gráfico muda e nada é salvo.

Veja-o rodando no cartão Simplifique o gráfico.

Regras ​

UI.simplify.rules é uma lista ordenada. Cada regra fornece uma chave a alguns nós, e os nós que compartilham uma chave tornam-se um grupo, desde que haja pelo menos minSize deles.

  • As regras são executadas em ordem, e cada uma vê os grupos que as regras acima criaram como nós comuns. Um grupo pode, portanto, ser agrupado novamente por uma regra posterior.
  • As regras são executadas após os filtros de nó, então um grupo retém apenas o que passa por eles: oculte três dos quarenta IPs e o grupo lê 37. As camadas de borda não mudam de grupo; desligar um apenas oculta as linhas.
  • Um nó com uma nota anexada e um cluster expandido nunca são agrupados. Um cluster fechado agrupa como qualquer outro nó.
  • Uma regra declarada está ativada, a menos que diga enabled: false.

Sem UI.simplify, o modo full oferece as regras integradas desativadas no modo Simplify rail; os outros modos não executam nada. UI.simplify.enabled: false remove o recurso.

A regra do vizinho ​

ts
{ kind: 'neighbours', minSize: 5, typeOf: (node) => node.getData().type }

Ele dobra nós de um tipo que se vinculam a exatamente os mesmos nós, da mesma maneira: os mesmos nós apontando para eles e os mesmos nós para os quais eles apontam. As folhas de um cubo são o caso mais simples. Com os eventos A e B compartilhando três TTPs e cada um tendo dois próprios, você obtém três grupos: os três compartilhados entre A e B e dois de cada lado.

  • O tipo é o próprio typeOf da regra, senão UI.simplify.typeOf, senão render.nodeTypeAccessor. Nós sem grupo de tipos entre si.
  • Um nó ligado a nada nunca é agrupado: um grupo precisa de algo para se pendurar.
  • Um nó que ganha um link sai do seu grupo para aquele que corresponde aos seus novos vizinhos. Se sobrar menos de minSize, o grupo se dissolve.
  • Um grupo mantém sua identidade enquanto mantém a maioria de seus membros, portanto, um novo nó que chega com os mesmos vizinhos se junta ao grupo existente sem movê-lo.

A regra da cadeia ​

ts
{ kind: 'chains', minSize: 5, typeOf: (node) => node.getData().type }

Ele dobra correntes que ficam penduradas em um nó. Um evento contendo trinta arquivos, cada um com seu próprio hash, equivale a trinta cadeias file > sha256: os arquivos não compartilham nenhum vizinho, já que cada um vincula seu próprio hash, então a regra do vizinho os deixa em paz. A regra da cadeia os agrupa em um grupo de arquivos vinculados a um grupo de hashes e desenha os trinta links entre eles como uma linha.

  • O tail de um nó é um nó cujo único link vem dele, seguido a jusante enquanto cada etapa liga apenas ao longo da cadeia. Um nó ligado a dois outros, um ramo ou um ciclo, encerra aí a cadeia.
  • Nós que conduzem cadeias do mesmo formato se dobram, quando compartilham os mesmos outros links e tipo. Cinco pares isolados domain → ip fornecem um grupo de cinco domínios vinculados a um grupo de cinco IPs.
  • Cada nível das correntes também se dobra: sob o grupo de suas cabeças, ou sob uma cabeça própria quando não há correspondência.
  • Contagem de links apenas downstream: um nó cujo único link aponta para outro não é a cauda desse nó.
  • Colocado após a regra do vizinho, ele dobra o que sobrou dessa regra. Um grupo criado pela regra do vizinho pode ser uma cauda.
ts
{ kind: 'degree', minDegree: 2 }
{ kind: 'kcore', k: 2 }

Essas regras retiram os nós da tela de acordo com o quão bem vinculados eles estão e os agrupam nos nós nos quais estão pendurados, para que a contagem permaneça na tela:

  • Poucos links (degree) dobra nós com menos de minDegree links: em 2, as folhas de um hub se tornam um grupo no hub.
  • Fora do núcleo (kcore) remove nós com menos de k links e, em seguida, faz isso novamente com o que resta, até que cada nó em pé tenha k links entre os outros. Em 2, ele dobra árvores inteiras penduradas no gráfico, não apenas suas folhas.

Nós dobrados que tocam os mesmos nós restantes compartilham um grupo, quaisquer que sejam seus tipos, e um grupo pode conter um único nó: lê-se "mais 1" em sua âncora. Nós dobrados e vinculados entre si vão para o mesmo grupo, de modo que um caminho pendurado em um hub se dobra com as folhas do hub. Uma série de nós dobrados que não tocam em nada restante é um grupo próprio, e cada nó vinculado a nada compartilha um grupo. Ambas as configurações vão de 1 a 10 e os links contam de qualquer maneira.

Após a regra do vizinho, um grupo é um nó para estas regras: seus links são suas linhas. Um grupo pendurado sozinho em sua âncora permanece como está.

Comunidades ​

ts
{ kind: 'communities', level: 4 }

Para grafos muito grandes para as regras acima, Comunidades dobra vizinhanças inteiras: nós mais densamente ligados uns aos outros do que ao resto do grafo tornam-se um grupo, quaisquer que sejam os seus tipos. Eles são encontrados com o algoritmo de Leiden, sempre o mesmo para o mesmo gráfico.

  • level vai de 1, fino, muitas comunidades pequenas, para 7, grosseiro, um punhado de comunidades grandes. No modo Simplificar é um controle deslizante, aplicado quando você solta.
  • As comunidades são encontradas em um trabalhador, fora da página, e somente novamente quando a forma do gráfico muda. Enquanto isso, o cartão diz Agrupamento… e os grupos anteriores permanecem. Onde nenhum trabalhador pode iniciar, uma Política de Segurança de Conteúdo bloqueando trabalhadores de blob, por exemplo, o mesmo código é executado na página; useWorker: false pede isso.
  • Uma comunidade de um nó permanece um nó e os nós anotados ficam de fora, como acontece com todas as regras.
  • Ao contrário das outras regras integradas, as Comunidades apenas estão no modo Simplificar quando declaradas.

Desembarques pivô ​

ts
{ kind: 'landings', minSize: 2 }

Ingerir em um grupo, no rodapé do painel pivot Revisão, coloca as linhas selecionadas dobradas: um grupo por tipo, pendurado no nó em que você girou. Quarenta IPs chegam como “40 × ip” em vez de quarenta pontos.

  • Um grupo contém o que é ingerido added. Um nó que já estava na tela permanece onde estava.
  • Um membro fica seja lá o que for vinculado posteriormente, ao contrário da regra do vizinho. Retire-o, exclua-o ou desfaça a ingestão para retirá-lo. Desfazer dissolve o grupo e refazer o traz de volta.
  • Um tipo com menos nós que minSize (2 por padrão) chega como nós simples.
  • A regra é executada primeiro, portanto, as regras posteriores veem cada patamar como um nó. Não é necessário declará-lo: o primeiro patamar agrupado adiciona-o no topo do modo Simplificar, ativado. Declare-o para colocá-lo em outro lugar ou altere seu menor grupo.
  • Quais patamares são agrupados duram a sessão, como grupos abertos.
  • O landing de um grupo de destino nomeia de onde ele veio: { runId, pivotId, pivotLabel }, com o rótulo da definição do pivô. Um chip pode ler 12 × ip · Event elements sem analisar o ID de execução.

Para obter todos os resultados do pivô agrupados, defina pivotIngestGrouped. Execuções com um clique e pivôs autoIngest, que nunca abrem Revisão e depois são agrupados também:

js
new Pivotick(el, data, { pivotIngestGrouped: true })

O rodapé da revisão segue a opção:

pivotIngestGroupedIngerir selecionados e Ingerir todosSegundo botão
desativado (padrão)terra soltaIngerir em grupo
ligadoterreno agrupadoIngerir solto

Com UI.simplify desligado, a opção não faz nada e não há segundo botão.

Para escolher uma ingestão do código, passe group:

js
await graph.pivots.ingest('correlations', 'triage', { group: true })

Regras personalizadas ​

Uma regra própria é partition(view) retornando uma chave por nó:

ts
{
    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 é o gráfico conforme esta regra o vê:

MembroO que é isso
nodesOs nós que esta regra pode agrupar: o que passa nos filtros, com grupos de regras anteriores no lugar de seus membros. Nós anotados, nós extraídos e clusters expandidos são deixados de fora.
inNeighbours(node) / outNeighbours(node)Os nós desenhados com uma linha de ou para este.
typeOf(node)O tipo de regra agrupa por: UI.simplify.typeOf, senão render.nodeTypeAccessor.
groupOf(node)O grupo por trás de um nó, quando for um nó criado por uma regra anterior.

Um nó deixado de fora do mapa permanece ele mesmo e os ids que não estão em view.nodes são ignorados. Uma regra que lança é desativada, seu cartão no modo Simplificar diz isso e as outras regras ainda são executadas.

O modo Simplificar ​

O botão Simplify no trilho abre um cartão por regra, em ordem de execução: uma opção, sua configuração e o que a regra dobrou. A configuração é um passo − / + para o menor grupo, o menor número de links ou a força principal e um controle deslizante para o nível de Comunidades. As regras declaradas pelo aplicativo carregam uma tag app. O resumo na parte superior mostra quantos nós estão na tela de quantos passam nos filtros, e o botão de trilho conta os grupos enquanto qualquer regra é dobrada.

Trabalhando com um grupo ​

Um grupo é desenhado como um nó e atua em nome de seus membros sempre que isso não for ambíguo.

  • Abra com um clique duplo, Enter, na barra lateral ou no menu de contexto. Seus membros voltam como nós comuns, dentro de uma lavagem na cor do grupo, e um leve puxão os mantém juntos. Arraste a ficha acima deles para mover todos; seu × os dobra para trás. Sua dica nomeia a regra que criou o grupo. Os membros voltam para onde estavam sentados; aqueles que não têm espaço livre espalham-se pelo grupo, e a física ao vivo recebe um leve empurrão, como acontece com um aglomerado. simulation.fitViewOnExpandCollapse ajusta-se à visualização de abertura e fechamento. Um grupo com mais membros que UI.simplify.openConfirmAbove (100) pergunta primeiro.
  • Selecione para ver seus membros na barra lateral, em uma lista classificável. Retirar mantém um membro fora do grupo até que ele seja colocado de volta, em seu menu de contexto: na tela enquanto o grupo está aberto, ou em sua linha no data dock, esteja o grupo aberto ou não. Sobre uma seleção, ele retira todos os membros selecionados.
  • Ver na tabela, na barra lateral ou no menu de contexto, lista os membros no banco de dados, onde os filtros de coluna os restringem ainda mais. O chip acima da tabela lista todos os nós novamente.
  • Selecionar membros, Pivot e Delete atuam nos membros. Pivot e Delete passam pelos ganchos usuais, então onBeforeDelete vê os nós reais. Ocultar, Excluir e Girar em uma seleção que mantém os grupos agindo sobre seus membros também.
  • Selecionar um grupo ilumina os nós aos quais ele está vinculado, assim como selecionar um nó ilumina seus vizinhos. A edição e a conexão não são oferecidas em um grupo: ele não possui dados próprios.

Grupos abertos e nós extraídos duram a sessão e não são etapas de desfazer. Para restaurá-los, chame graph.simplify.open() e pullOut().

Grupos feitos à mão ​

Selecione dois nós ou mais e, em seguida, Grupo na barra em massa da barra lateral ou Agrupar nós selecionados no menu de contexto de um nó selecionado. Digite um título ou mantenha o oferecido (“3 × ip, 2 × domínio”) e a seleção se agrupará em um grupo sob esse título.

  • Um grupo feito à mão vence. Sua regra, Manualmente, é executada antes de todas as outras, então um nó escolhido sai de qualquer grupo de regras. Um grupo selecionado fornece seus membros e um nó selecionado em um segundo grupo feito à mão deixa o primeiro. Nós anotados e clusters abertos ficam de fora e o prompt informa quantos.
  • Ele mantém seus membros seja lá o que eles vincularem. Aquele que é excluído ou filtrado não é sorteado; um grupo que fica com um membro não é sorteado e volta com seus membros.
  • Renomear e Desagrupar no painel da barra lateral ou no menu de contexto. Um título vazio rotula-o novamente por seus tipos. O Ungroup da barra em massa remove todos os grupos feitos à mão que a seleção contém ou nos quais se encontra.
  • Agrupar, Renomear e Desagrupar são etapas de desfazer, ao contrário de abrir ou retirar.
  • É o estado de visualização: não exportado e recarregado. Para mantê-lo, salve getManualGroups() e devolva para setManualGroups(). Grupos restaurados, abertos ou retirados logo após new Graph() fazem parte do layout de abertura: um grupo fechado é colocado como um ponto, um aberto os membros são mantidos juntos.
js
const id = graph.simplify.groupNodes(['ip-1', 'ip-2', 'dom-7'], 'Suspicious infra')
graph.simplify.renameGroup(id, 'Cleared infra')
graph.simplify.ungroup(id)

Procurando ​

A pesquisa examina cada nó, incluindo os dobrados.

  • Uma correspondência dentro de um grupo diz isso em sua linha de resultados: in 12 × ip.
  • Selecioná-lo abre o grupo e seleciona o nó, como Selecionar membros faria. Um grupo com mais membros que openConfirmAbove permanece fechado e é selecionado.
  • Mostrar tudo na tela, a última linha dos resultados ou Shift+Enter, fecha a pesquisa e ilumina todas as correspondências; todo o resto desaparece. Um grupo segurando fósforos também está aceso, e um arco na cor do tema acima do anel mostra sua participação. Sua dica de ferramenta os conta: 2 de 12 corresponde a "198,51". Esc, um clique na tela vazia ou a próxima pesquisa encerra.

Passar o mouse sobre uma entrada de legenda marca grupos da mesma maneira: um grupo que contém nós dessa entrada é aceso, com sua parte em seu anel, portanto, um grupo que mistura tipos não é lido como um todo.

Um aplicativo com pesquisa própria pode marcar suas correspondências da mesma forma com graph.simplify.setMatches(nodes, query) e limpá-las com setMatches([]).

O olhar ​

Um grupo é um anel em torno de um disco na cor do seu tipo, com a contagem no disco quando houver espaço para ele e uma etiqueta abaixo. Cresce com a sua contagem, até um limite. Um grupo de tipos de mixagem obtém um disco neutro e um anel dividido por tipo.

O rótulo é 12 × ip por padrão. typeLabel nomeia seus tipos:

ts
UI: {
    simplify: {
        typeLabel: (type, count) => `${count} ${count === 1 ? type : `${type}s`}`,
    },
}

render.groupStyle(group) retorna um NodeStyle em camadas sobre o padrão, então tiers, html, shape e emblemas funcionam em um grupo como em um nó. render.groupOutline(group) define o que diz o chip sobre um grupo aberto:

ts
render: {
    groupStyle: (group) => group.rule === 'bySensor' ? { color: '#6b7280' } : undefined,
    groupOutline: (group) => `${group.members.length} from ${group.rule}`,
}

groupStyle também recebe base, o estilo que a biblioteca desenharia. O que você retorna substitui suas chaves, portanto, um host que adiciona uma camada se espalha base.tiers para manter a contagem no disco:

ts
render: {
    groupStyle: (group, base) => ({
        tiers: [...(base.tiers ?? []), { width: 140, height: 44, style: { html: () => chip(group) } }],
    }),
}

Cada um recebe um GroupInfo:

CampoO que é isso
idEstável enquanto o grupo mantém a maioria de seus membros.
rule'neighbours', 'chains', 'degree', 'kcore', 'communities', 'landings', 'manual' ou id de uma regra personalizada.
membersOs nós reais que ele representa.
typeCountsQuantos membros de cada tipo; '' não é nenhum tipo.
anchorsOs nós desenhados aos quais ele se vincula, grupos incluídos.
openSe seus membros estão de volta à tela.
levelO nível de Comunidades em que foi encontrado.
titleO título de um grupo feito à mão.
landingA corrida e o pivô de um grupo de pouso: { runId, pivotId, pivotLabel }.

A dica de ferramenta de um grupo nomeia sua regra, lista seus links e, para um grupo misto, seus membros por tipo. tooltip.renderGroupExtra(group, ctx) adiciona suas próprias linhas, como renderNodeExtra faz para um nó. Um grupo ignora tooltip.render e renderNodeExtra, que são gravados para os dados de um nó.

Tipos e cores do host ​

Os grupos contam suas partes por render.nodeTypeAccessor e as colorem de acordo com a cor do estilo de cada membro. Duas opções UI.simplify alteram isso para cada regra e grupo, sem tocar nos estilos, na legenda ou nos filtros:

  • typeOf(node) é o tipo pelo qual cada grupo de regras e cada grupo conta suas partes: o rótulo, as ações de um anel misto, o título de um grupo feito à mão. O próprio typeOf de uma regra ainda vence para essa regra.
  • colorOf(node) é a cor que um nó representa em um grupo: o disco e o anel, a lavagem aberta, os chips da dica de ferramenta. Retornar undefined retorna à cor de estilo do nó. O próprio groupStyle do grupo ainda tem a última palavra no sorteio encerrado.

Um host que estiliza por elemento, agrupa por subtipo e desenha ele mesmo seus nós:

ts
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],
        },
    },
}

Na mesa ​

O data dock lista os nós reais. Um nó dobrado lê grouped na coluna Visibility, e uma coluna Group nomeia seu grupo enquanto houver algum. Uma aresta cuja linha é desenhada para um grupo também indica grouped.

Em tempo de execução ​

graph.simplify contém as regras e os grupos:

MétodoO que isso faz
setRules(rules) / getRules()Substitua as regras; leia o estado de cada um e o que ele dobrou.
setRuleEnabled(id, on) / setRuleSetting(id, n)O que o switch e o stepper do modo Simplificar fazem. setRuleMinSize(id, n) define apenas um grupo menor.
getGroups() / groupOf(node)Cada grupo e o primeiro grupo em que um nó foi incorporado. Um grupo cuja regra posterior foi dobrada novamente também é listado, ao lado do grupo que o detém, e ambos listam seus membros; summary().groups conta os grupos fechados que a tela desenha.
open(group) / close(group)Coloque os membros de um grupo na tela ou dobre-os.
pullOut(node) / putBack(node) / isPulledOut(node)Mantenha um nó fora de qualquer grupo ou deixe-o voltar.
groupNodes(nodes, title?) / renameGroup(group, title) / ungroup(groups) / isManual(group)Crie, renomeie ou remova grupos manualmente; cada um é uma etapa de desfazer.
getManualGroups() / setManualGroups(list)Salve os grupos feitos à mão e restaure-os.
groupLanding(runId) / ungroupLanding(runId) / isLandingGrouped(runId)Dobre o que uma corrida pivô adiciona em grupos de pouso ou solte-o novamente.
summary()Quantos nós são desenhados, passam pelos filtros e são dobrados.
setMatches(nodes, query) / matchesIn(group)Marque as correspondências de uma pesquisa nos grupos que as possuem; leia quantos um grupo contém.
onChange(listener)Chamado após as alterações de agrupamento; retorna seu cancelamento de assinatura.