Processamento de consultas contínuas contendo preferências condicionais
4.2 Algoritmos baseados em grafos
de remoção e de inserção. Deste modo, o custo para processar tal operador é de O(1). O operador TOPK, por sua vez, é processado pelo algoritmo IncAncestorsTopk cujo custo está relacionado com o número de iterações dos laços de repetição. O número de iterações do laço mais externo é igual ao nível de preferência máximo da teoria-pc, já o laço interno é executado uma vez para cada tupla de R. Desta maneira, a complexidade do algoritmo IncAncestorsTopk é O(nm).
4.2 Algoritmos baseados em grafos
Os algoritmos baseados em grafos mantêm um BTG com as tuplas da relação em memória que é atualizado a cada instante. Dada uma relação R e uma teoria-pc Γ, o BTG de R é representado pela estrutura Graph(Anc#, Succ#, Best). O conjunto Anc#(t) contém as tuplas que dominam t, o conjunto Succ#(t) representa as tuplas dominadas por t e Best é o conjunto das tuplas dominantes. Esta seção apresenta uma adaptação do algoritmo baseado em grafos proposto em Petit et al. (2012) para que seja considerada a ordem de preferência sobre o conjunto de todas as tuplas do esquema relacional. Esta adaptação se faz necessária para que todos os algoritmos analisados neste capítulo tenham a mesma semântica e possam ser comparados mais adequadamente.
Operação de remoção
O algoritmo GraphDelete (Algoritmo 12) é responsável pela tarefa de remoção. Para cada tupla removida t ∈ ∆−, o algoritmo veriĄca se t é uma tupla dominante e a remove do conjunto de tuplas dominantes Best. Em seguida, o algoritmo remove as arestas relacionadas à tupla t. Lembrando que as arestas são representadas pelas entradas nas estruturas Anc# e Succ#.
Algoritmo 12 Ű GraphDelete(∆−)
Entrada: Conjunto de tuplas removidas ∆−
Atualização: Arestas do grafo (Anc# e Succ#), conjunto de tuplas dominantes Best
1: for all t ∈ ∆− do //Para cada tupla t removida
2: if t ∈ Best then //Checa se t é dominante 3: Best ← Best − ¶t♢ //Remove t do conjunto Best 4: for allt′ ∈ Anc#(t) do //Para cada tupla t′ que domina t 5: Succ#(t′) ← Succ#(t′) − ¶t♢ //Remove t do conjunto de tuplas dominadas por t′ 6: for allt′′∈ Succ
#(t) do //Para cada tupla t′′ dominada por t 7: Anc#(t′′) ← Anc#(t′′) − ¶t♢ //Remove t do conjunto de tuplas que domina t′′ 8: Anc#.del(t) //Remove a entrada t de Anc#
Operação de inserção
O algoritmo GraphInsert (Algoritmo 13) realiza a tarefa de inserção. O algoritmo compara cada tupla t inserida com cada tupla t′ já existente na relação R. Quando t domina t′, o algoritmo acrescenta uma aresta de t para t′ e remove t′ do conjunto Best, caso t′ seja um tupla dominante. Por outro lado, se t′ domina t, o algoritmo adiciona uma aresta de t′ para t e marca t como dominada. Após as iterações do laço mais interno, a tupla t é inserida no conjunto Best, se a mesma não foi dominada.
A adaptação em relação ao trabalho original de Petit et al. (2012) aconteceu exatamente na tarefa de inserção. No trabalho original o teste de dominância considerava apenas as tuplas existentes na relação. Nesta adaptação o teste de dominância usa a estratégia de busca que considera a ordem de preferência imposta sobre Tup(R), assim como acontece na abordagem em listas de antecessores.
Algoritmo 13 Ű GraphInsert(Γ, ∆+)
Entrada: Teoria-pc Γ e conjunto de tuplas inseridas ∆+
Atualização: Arestas do grafo (Anc# e Succ#), conjunto de tuplas dominantes Best
1: for all t ∈ ∆+ do //Para cada tupla t inserida
2: dominated ← false //Pressupõe que t não será dominada
3: for allt′ ∈ R do //Para cada tupla t′ já existente
4: if t ≻Γt′ then //Testa se t domina t′
5: Succ#(t) ← Succ#(t) ∪ ¶t′♢ //Insere t′ entre as tuplas dominadas por t 6: Anc#(t′) ← Anc#(t′) ∪ ¶t♢ //Insere t entra as tuplas que dominam t′ 7: if t′ ∈ Best then //VeriĄca se t′ era dominante
8: Best ← Best − ¶t′♢ //Remove t′ do conjunto de tuplas dominantes
9: else if t′ ≻Γt then //Testa se t′ domina t
10: dominated ← true //Marca t como dominada 11: Succ#(t′) ← Succ#(t′) ∪ ¶t♢ //Insere t entre as tuplas dominadas por t′ 12: Anc#(t) ← Anc#(t) ∪ ¶t′♢ //Insere t′ entra as tuplas que dominam t
13: if notdominated then //VeriĄca se t não foi dominada
14: Best ← Best ∪ ¶t♢ //Adiciona t entra as tuplas dominantes
Obtenção das top-k tuplas
O algoritmo IncGraphTopk (Algoritmo 14) realiza o processamento do operador
TOPK por meio de uma ordenação topológica no grafo (KAHN, 1962). O algoritmo cria
cópias das estruturas Best e Anc# para Best′ e Anc′#, respectivamente. Esta cópia tem o objetivo de preservar as estruturas Best e Anc# que são alteradas durante a ordenação topológica. A lista L é utilizada para ordenar as tuplas, de forma que uma tupla t é adicionada à L somente se todas as tuplas que dominam t já estiverem em L.
Inicialmente, o conjunto Best′ contém as tuplas com nível de preferência igual a zero, ou seja, as tuplas dominantes. A cada iteração, as tuplas do conjunto Best′ com nível
4.2. Algoritmos baseados em grafos 85
Algoritmo 14 Ű IncGraphTopk(R, k)
Entrada: Relação R e número de top-k tuplas desejadas k Saída: Top-k tuplas da relação R
1: Best′ ← Best //Copia Best para Best′
2: Anc′
#← Anc# //Copia Anc#para Anc′#
3: L ← NewList() //Cria lista L para ordenar tuplas 4: while (♣L♣ < k) and (♣L♣ < ♣R♣) do //Enquanto ♣L♣ < k e ♣L♣ < ♣R♣ 5: N ← ¶♢ //Tuplas a serem processadas na próxima iteração 6: for allt ∈ Best′ do //Para cada tupla t dominante (na iteração atual) 7: L.append(t) //Adiciona t à lista L 8: for all t′∈ Succ#(t) do //Para cada tupla t′ dominada por t
9: Anc′
#(t′) ← Anc′#(t′) − ¶t♢ //Remove a aresta de t para t′ 10: if ♣Anc#(t′)♣ = 0 then //VeriĄca se t′ deixou de ser dominada 11: N ← N ∪ ¶t′♢ //Insere t′ em N
12: Best′ ← N //Move tuplas de N para Best′
13: return L.getFirst(k) //Retorna as k primeiras tuplas de L
de todas as iterações, a lista L possuirá as tuplas de R ordenadas pelo nível de preferência. Ao Ąnal, o algoritmo retorna as k primeiras tuplas de L. O Exemplo 13 apresenta uma possível execução dos algoritmos baseados em grafo.
Exemplo 13 (Execução do algoritmo IncGraphTopk). Considere novamente a relação
acoes e a teoria-pc Γ do Exemplo 12. No instante i, o BTG da relação é representado pelas seguintes estruturas:
• Anc#(t1) = Anc#(t6) = ¶♢; • Anc#(t2) = ¶t1♢; • Anc#(t3) = Anc#(t4) = ¶t1, t2♢; • Anc#(t5) = ¶t1, t2, t3♢; • Succ#(t1) = ¶t2, t3, t4, t5♢; • Succ#(t2) = ¶t3, t4, t5♢; • Succ#(t3) = ¶t5♢
• Succ#(t4) = Succ#(t5) = Succ#(t6) = ¶♢; • Best = ¶t1, t6♢.
Considere novamente a remoção das tuplas t3 e t6 no instante i + 1. A execução do algoritmo GraphDelete ocorre da seguinte maneira:
1) Remoção da tupla t6:
a) A tupla t6 é removida do conjunto Best;
b) Nenhuma aresta é alterada pelo fato de t6 ser incomparável às demais tuplas; c) A tupla t6 é removida das estruturas Anc# e Succ#.
a) Como as tuplas t1 e t2 dominam t3 (Anc#(t3) = ¶t1, t2♢), o algoritmo remove t3 de
Succ#(t1) e de Succ#(t2). Portanto, Succ#(t1) = ¶t2, t3, t4, t5♢ − ¶t3♢= ¶t2, t4, t5♢ e
Succ#(t2) = ¶t3, t5♢ − ¶t3♢= ¶t5♢;
b) Como t3 domina t5 (Succ#(t3) = ¶t5♢), o algoritmo remove t3 de Anc#(t5). Portanto,
Anc#(t5) = ¶t1, t2, t3♢ − ¶t3♢= ¶t1, t2♢;
c) A tupla t3 é removida das estruturas Anc# e Succ#.
Já a execução do algoritmo GraphInsert acontece do seguinte modo: 1) Inserção da tupla t7:
a) A tupla t7 domina a tupla t5, então Anc#(t5) = ¶t1, t2♢ ∪ ¶t7♢ = ¶t1, t2, t7♢ e
Succ#(t7) = ¶t5♢;
b) Como t7 não é dominada, a mesma é adicionada ao conjunto Best. 2) Inserção da tupla t8:
a) A tupla t8 é dominada pela tupla t1, então Anc#(t8) = ¶t1♢ e Succ#(t1) = ¶t2, t4, t5♢ ∪ ¶t8♢= ¶t2, t4, t5, t8♢;
b) A tupla t8 domina a tupla t4, então Anc#(t4) = ¶t1, t2♢ ∪ ¶t8♢ = ¶t1, t2, t8♢ e
Succ#(t8) = ¶t4♢;
c) A tupla t8 domina a tupla t5, então Anc#(t5) = ¶t1, t2, t7♢ ∪ ¶t8♢= ¶t1, t2, t7, t8♢ e
Succ#(t8) = ¶t4♢ ∪ ¶t5♢= ¶t4, t5♢;
d) A tupla t8 não é adicionada ao conjunto Best pelo fato de ter sido dominada. Por Ąm, a execução do algoritmo IncGraphTopk é realizada da seguinte maneira: 1) O algoritmo cria as cópias Anc′
#e Best′ para as estruturas Anc#e Best, respectivamente. O algoritmo também cria a lista L;
2) Como L está vazia, o laço inicia as iterações;
3) Na primeira iteração, as tuplas de Best′ são inseridas em L. Além disto, as tuplas t 2 e
t8 passam a compor o conjunto Best′ na próxima iteração;
4) Na segunda iteração as tuplas t2 e t8 são adicionadas à lista L e o conjunto Best′ para a próxima iteração contém as tuplas t4 e t5;
5) Como L possui mais de três tuplas o laço é interrompido e o algoritmo retorna as três primeiras tuplas da lista L = [t1, t7, t2, t8].
Análise de complexidade
A complexidade do algoritmo GraphDelete é de O(nδ− + n × ♣Anc
#(t)♣ + n × ♣Succ#(t)♣) onde n = ♣R♣ e δ− = ♣∆−♣. Assumindo também um fator de limitação para as estruturas ♣Anc#(t)♣ e ♣Succ#(t)♣, assim como foi feito para a lista de antecessores, a complexidade do algoritmo GraphDelete é de O(nδ−). Já a complexidade do algoritmo