NATÁLIA CRISTINA SCHNEIDER SIMDATAMAPPER: UM PADRÃO ARQUITETURAL PARA INTEGRAÇÃO DE OPERAÇÕES DE SIMILARIDADE TEXTUAL EM SISTEMAS DE BANCO DE DADOS LAVRAS – MG 2014 NATÁLIA CRISTINA SCHNEIDER SIMDATAMAPPER: UM PADRÃO ARQUITETURAL PARA INTEGRAÇÃO DE OPERAÇÕES DE SIMILARIDADE TEXTUAL EM SISTEMAS DE BANCO DE DADOS Trabalho de Conclusão de Curso de Graduação apresentado ao Colegiado do Curso de Bacharelado em Ciência da Computação, para obtenção do título de Bacharel. Orientador Prof. Dr. Leonardo Andrade Ribeiro Coorientador Prof. Dr. Ahmed Ali Abdalla Esmin LAVRAS – MG 2014 Dedico à minha família, em especial aos meus pais, Edemilson e Maria Luiza . AGRADECIMENTOS Quero agradecer aos meus pais Maria Luiza e Edemilson pelo apoio, dedicação, esforço e pelo amor incondicional durante esta fase. Aos meus irmãos Renan e Guilherme por acreditarem em mim em todos os momentos. Ao meu namorado Vinicius por toda a paciência e compreensão. Aos familiares que sempre estiveram presentes. Aos amigos de Rio Claro que compreenderam a minha ausência. Aos amigos de Lavras quero agradecer pelo companheirismo e amizade durante toda esta trajetória, vocês fizeram que esta etapa fosse inesquecível. SUMÁRIO 1. INTRODUÇÃO ............................................................................................. 10 2. TRABALHOS RELACIONADOS .............................................................. 11 3. CONCEITOS BÁSICOS .............................................................................. 12 3.1. Mapeamento de Strings para Conjuntos ...................................................... 12 3.2. Esquema de Pesos ........................................................................................ 12 3.3. Funções de Similaridade .............................................................................. 13 3.4. Funções de Similaridade baseadas em Conjuntos........................................ 13 3.5. Filtros baseados em Tamanho ...................................................................... 14 3.6. Função de Similaridade baseada em Distância de Edição ........................... 14 3.7. Prefix Filtering ............................................................................................. 15 3.8. Design Pattern e Data Mapper Pattern ......................................................... 15 4. SIMDATAMAPPER .................................................................................... 16 5. IMPLEMENTAÇÃO.................................................................................... 17 5.1. Implementação das Funções de Similaridade baseadas em Conjuntos ....... 18 5.2. Implementação da Função de Similaridade baseada na Distância de Edição ......................................................................................................... 21 5.3. Implementação do Prefix Filtering ............................................................. 22 5.4. Implementação SimDataMapper ................................................................ 23 6. EXPERIMENTOS ....................................................................................... 23 6.1. Dados .......................................................................................................... 23 6.2. Seleções por Similaridade ........................................................................... 23 6.3. Junções por Similaridade ............................................................................ 25 6.4. Prefix Filtering ........................................................................................... 25 6.5. Atualizações de estatísticas ......................................................................... 26 7. CONCLUSÃO ............................................................................................. 27 REFERÊNCIAS BIBLIOGRÁFICAS .......................................................... 28 APÊNDICE A .................................................................................................. 29 LISTA DE FIGURAS Figura 1 - Mapeamento de uma string para um conjunto de tokens .................12 Figura 2 - SimDataMapper.................................................................................16 Figura 3 - Diagrama de sequência da operação que constrói o suporte a operações de similaridade....................................................................................17 Figura 4 - Diagrama de sequência da operação Retrieve....................................17 Figura 5 - Diagrama de sequência da operação Update ....................................17 Figura 6 - Digrama de classe SimDataMapper..................................................24 Figura 7 - Gráfico das seleções do Estágio 2.....................................................24 Figura 8 - Gráfico das seleções do Estágio 3.....................................................24 Figura 9 - Gráfico das seleções do Estágio 4.....................................................25 Figura 10 - Gráfico das Junções.........................................................................25 Figura 11 - Criação das tabelas de prefixo ........................................................26 Figura 12 - Tempo de execução da junção com Prefix Filtering.......................26 Figura 13 - Comparação do tempo de execução com e sem prefixo..................26 Figura 14 - Gráfico da propagação de estatística ..............................................27 LISTA DE TABELAS Tabela 1 – Funções de Similaridade baseadas em conjunto...............................13 Tabela 2 – Filtros baseados em tamanho............................................................14 Tabela 3 – Relação de tabelas por estágios........................................................17 Tabela 4 – Tempo de criação das tabelas auxiliares...........................................24 SimDataMapper: um Padrão Arquitetural para Integração de Operações de Similaridade Textual em Sistemas de Banco de Dados Natália Cristina Schneider1 Leonardo Andrade Ribeiro2 1 Universidade Federal de Lavras, Departamento de Ciência da Computação, Brasil Federal de Góias, Instituto de Informática, Brasil [email protected], [email protected] 2 Universidade Keywords: Banco de Dados, Operações de Similaridade, Processamento Avançado de Consultas, Integração de Dados, Identificação de Duplicatas Abstract: Dados textuais são onipresentes, por isso gerenciar esses tipos dados é de fundamental importância. Neste cenário, a duplicação de informação é algo comum em sistemas de banco de dados, principalmente em decorrência de erros ortográficos e da falta de um padrão representativo. Consequentemente, operações baseadas em noções de similaridade são essenciais para a manutenção consistente dos dados armazenados. Entretanto, operações de similaridade não são suportadas nativamente por sistemas gerenciadores de banco de dados atuais. Por exemplo, no caso de junções, a implementação mais direta baseada em procedimentos armazenados realiza os cálculos de similaridade sobre a saída do produto cartesiano entre duas tabelas, e, com isso, apresenta tempo de execução excessivamente alto, mesmo para volumes moderados de dados. Para mitigar este problema, uma série de trabalhos foram propostos que utilizam diversos filtros para reduzir o espaço de comparação e expressam comparações baseadas em similaridade declarativamente em SQL. Por outro lado, apesar de permitir ganhos significativos de performance, estas estratégias dificultam consideravelmente o acesso transparente e integração de programas de aplicação ao banco de dados. Por exemplo, o suporte a operações por similaridade sobre um simples atributo requer a construção, acesso e manutenção de várias tabelas auxiliares. Este artigo apresenta um padrão arquitetural de software para permitir a integração de operações baseadas em diversas noções de similaridade e aplicações orientadas a objetos de maneira simples e flexível. Um conjunto abrangente de experimentos são reportados e demonstram que a abordagem proposta é flexível e permite a execução eficiente de uma variedade de operações de similaridade, incluindo consultas baseadas em seleções e junções e operações de atualização dos dados. 1 INTRODUÇÃO Sistemas hospitalares, sistemas comerciais, catálogos de produtos são apenas alguns exemplos de aplicações comuns que utilizam atributos textuais. Duplicação de informação é algo comum nesses sistemas, principalmente em decorrência de erros ortográficos e da falta de um padrão representativo. De fato, atributos textuais usados em um banco de dados para armazenar informações como endereço e nome de um cliente normalmente não asseguram uma formatação rígida durante a entrada dos dados. Por exemplo, considere uma empresa que possui diversas fontes de dados de clientes e a necessidade de relacionar estas fontes é muito comum. Um mesmo cliente pode estar presente em diferentes fontes e o seu nome pode estar armazenado de maneiras diferentes, ou seja, em uma fonte ele pode ter sido cadastrado com o seu primeiro nome seguido pelo sobrenome, em outra com o sobrenome seguido de seu primeiro nome, e ainda existe a possibilidade de possuir algum erro de digitação em uma terceira fonte. Neste cenário, a utilização de uma operação de junção baseada em comparações de igualdade será insuficiente. Mais ainda, além de relacionar fontes de dados diferentes, pode ser necessário realizar consultas de um determinado cliente que foi armazenado na mesma base de dados de duas ou mais formas diferentes. Neste caso, também não será adequado utilizar operações baseadas em testes de correspondência exata. Os cenários descritos ressaltam os problemas encontrados por aplicações que relacionam dados textuais. Pois a abordagem baseada em comparações de igualdade apresenta uma qualidade inferior do que a esperada, sendo ineficaz e muitas vezes inadequada. Como forma de diminuir o impacto causado por este rentes domínios de aplicação. Onde elementos comuns entre as diversas técnicas implementadas foram identificados e organizados com um padrão arquitetural de software. Com isso, além do desempenho computacional, critérios importantes no lado do desenvolvimento de aplicações como facilidade de desenvolvimento, composibilidade, reusabilidade de código também passam a ser considerados. Este padrão arquitetural visa facilitar a incorporação de operações de similaridade em sistemas de banco de dados, sem a necessidade de aquisição de produtos especializados. O restante deste artigo está estruturado da seguinte maneira. Trabalhos relacionados são discutidos na Seção 2. Os conceitos básicos necessários para o entendimento deste trabalho são apresentados na Seção 3. A apresentação do padrão arquitetural é apresentado na Seção 4. Estratégias para implementação são apresentadas na Seção 5. Na Seção 6 são apresentados os experimentos. Finalmente, as conclusões são apresentadas na Seção 7. problema é imprescindível a utilização de um paradigma mais geral, baseado no conceito de similaridade, onde seleções e junções são usadas para encontrar e relacionar objetos textuais similares em um banco de dados. Neste contexto, a similaridade entre dois objetos textuais é definida quantitativamente por uma função de similaridade. Existe uma variedade de funções de similaridade, entre as mais comuns estão a Cosseno, a Distância de Edição, a Dice e a Jaccard (Cohen, 1998). Para executar junções e seleções por similaridade é utilizado um limiar de corte e apenas tuplas ou pares de tuplas cujo valor retornado pela função de similaridade for maior que este limiar estarão presentes no resultado, neste caso estas tuplas são consideradas semelhantes. Infelizmente, operações de similaridade não são suportadas diretamente nos Sistemas Gerenciadores de Banco de Dados (SGBDs) atuais. Uma forma de implementar essas funções é através da utilização de UDFs (acrônimo do inglês User Defined Function). Entretanto, esta abordagem possui custo computacional proibitivamente alto. No caso de junções, a UDF é executada sobre o produto cartesiano das tabelas de entrada, o que faz com todos os pares de tuplas sejam comparados entre si. Com foco em dados do tipo texto, diversas propostas têm sido apresentadas nos últimos anos para contornar este problema, usando uma variedade de filtros para reduzir o espaço de comparação (Gravano et al., 2001; Koudas et al., 2007; Gravano et al., 2003; Koudas et al., 2004; Chandel et al., 2007). Entretanto, apesar de permitir ganhos significativos de performance, estas estratégias dificultam consideravelmente o acesso transparente e integração de programas de aplicação ao banco de dados. Por exemplo, o suporte a operações por similaridade sobre um simples atributo requer a construção, acesso e manutenção de várias tabelas auxiliares. O problema é exacerbado quando são usadas funções de similaridade que adotam esquemas de pesos para unidades textuais baseados em estatísticas, porque cada modificação na tabela original requer atualização e propagação de estatísticas para as tabelas auxiliares. Além disso, aplicações podem requerer o suporte a múltiplas funções de similaridade, pois é um fato conhecido que nenhuma função apresenta um melhor resultado em todos os domínios e cenários (Cohen et al., 2003). Com isso haveria a dificuldade de gerenciar um número maior ainda de tabelas auxiliares. Essas questões dificultam significativamente a adoção da similaridade declarativa por aplicações. Este artigo apresenta a modelagem e implementação do SimDataMapper, um padrão para suportar uma variedade de noções de similaridade em dife- 2 TRABALHOS RELACIONADOS Os trabalhos de pesquisa para o processamento de operações de similaridade sobre dados textuais podem ser agrupados de acordo com três abordagens gerais bastante relacionadas entre si: 1) implementação “no topo” do SGBD; 2) algoritmos especializados; 3) integração com mecanismos internos do SGBD. Na abordagem 1), operações de similaridade implementadas no topo do SGBD são expressas declarativamente em SQL e executadas usando infraestrutura puramente relacional, como índices agrupados baseados em árvores B e UDFs. Como mencionado anteriormente, trabalhos anteriores focaram em estratégias para suportar um conjunto diversificado de funções de similaridade (Gravano et al., 2001; Gravano et al., 2003; Koudas et al., 2004; Koudas et al., 2007; Chandel et al., 2007). Além da definição de um padrão arquitetural, vários outros aspectos diferenciam este trabalho de outros apresentados anteriormente (Koudas et al., 2007; Chandel et al., 2007). Primeiramente, existe a preocupação em definir um conjunto comum de tabelas auxiliares para suportar várias funções de similaridade. Além de considerar execução de junção e seleção de similaridade. Foram realizadas otimizações, como a utilização do Prefix Filtering. Finalmente, neste trabalho a propagação de estatística é feita proceduralmente em UDFs por questões de desempenho, se di- 11 o conceito de q-grams (Ukkonen, 1992), isto é, substrings de tamanho q obtidas através do “deslizamento de uma janela” de tamanho q sobre uma string. Como os tokens no início ou fim da string podem ser menores do que q e para garantir que cada caractere apareça em exatamente q tokens, a string é estendida no início e no fim. Neste caso a string é pré-fixada com q-1 ocorrências do caractere "#"e sufixada com q-1 ocorrências do caractere "$"(Koudas et al., 2004; Gravano et al., 2003) Por exemplo, a string “token” pode ser mapeada para o conjunto de 3-gram tokens apresentado na Figura 1. O resultado desse processo pode ser uma bag, neste caso, o símbolo de um número sequencial ordinal é anexado ao final de cada ocorrência de um token em uma string (Chaudhuri et al., 2006). Dessa maneira, a bag {a,b,b} é convertida para o conjunto {a1, b1, b2}. ferenciando novamente do que já foi apresentado em outros trabalhos (Koudas et al., 2007). A abordagem 2) consiste no desenvolvimento de algoritmos especializados (Sarawagi and Kirpal, 2004; Bayardo et al., 2007; Xiao et al., 2008; Ribeiro and Härder, 2011; Wang et al., 2012). Estas abordagens utilizam técnicas que não são facilmente reproduzidas por operadores relacionais e normalmente obtém performance superior a soluções implementadas no topo do SGBD. Finalmente, a abordagem 3) foca na integração de algoritmos de similaridade no núcleo do SGBD (Chaudhuri et al., 2006; Jr. et al., 2006; Augsten et al., 2014) (veja também (Ribeiro and Härder, 2007) e (Ribeiro et al., 2009) para SGBDs XML). Tipicamente, algoritmos especializados são integrados como operadores da álgebra física do SGBD. Esta abordagem requer modificações em todos os componentes do compilador de consultas como a álgebra lógica, modelo de custos e regras de compilação, além da extensão da linguagem de consulta para inclusão de construtores para operações de similaridade. O desenvolvimento de um sistema genérico para suportar várias operações de similaridade juntamente com a modelagem de um padrão arquitetural de software representa uma nova abordagem: 4) Integração de realização declarativa de operações de similaridade textual no ambiente de aplicação. Apesar deste aspecto ser fundamental para a disseminação do uso de operações de similaridade em sistemas de banco de dados, tem recebido pouca atenção na literatura. O trabalho proposto se encaixa na nova abordagem (4), que busca a integração com o ambiente de aplicação. 3 Figura 1: Mapeamento de uma string para um conjunto de tokens. CONCEITOS BÁSICOS 3.2 Nesta seção, são apresentados os principais componentes conceituais envolvidos em operações de similaridade. Incluindo a definição das funções de similaridade, transformação de strings para conjuntos, esquemas para associação de pesos e noções de similaridade baseadas em conjuntos e distância de edição. As operações de junção e seleção por similaridade são definidas formalmente. Finalmente, são apresentadas as vantagens de se utilizar o Data Mapper Pattern. 3.1 Esquema de Pesos Tokens podem possuir importância diferente para um determinado cálculo de similaridade. Neste caso, um esquema de pesos pode ser usado para quantificar a importância relativa de cada token através da associação de pesos a cada token. Um esquema de pesos que é amplamente conhecido é o IDF (acrônimo do inglês Inverse Document Frequency) (Baeza-Yates and Ribeiro-Neto, 2011), onde o peso de um token t é definido da seguinte maneira: IDF (t)=ln (N/df (t)), onde df (t) é o chamado document frequency (DF), isto é, o número de strings nas quais um token t aparece em um banco de dados de N strings. A intuição por trás de IDF é que tokens raros normalmente possuem mais conteúdo e são mais discriminativos. Neste tipo de associação tokens mais raros possuem um DF menor e consequentemente um IDF maior. Já os tokens que não são tão raros possuem um DF Mapeamento de Strings para Conjuntos A similaridade entre strings é calculada em termos de conjuntos de unidades básicas e indivisíveis de informação textual denominadas tokens. Strings podem ser mapeadas para conjuntos de tokens usando 12 Tabela 1: Funções de Similaridade baseadas em conjunto Função Jaccard Dice Cosseno Definição intersec (r, s) w (r ∩ s) w (r ∪ s) 2 · w (r ∩ s) w (r) + w (s) w (r ∩ s) p w (r) · w (s) τ · (w (r) + w (s)) 1+τ τ · (w (r) + w (s)) 2 p τ · w (r) · w (s) 2007; Xiao et al., 2008; Ribeiro and Härder, 2011; Wang et al., 2012), são apresentadas na Tabela 1. Exemplo 1. Considere os conjuntos r ={hc, 9i,hb, 7i,hd, 7i,he, 7i,hh, 5i,hi, 5i} e s ={ha, 10i,hc, 9i,hb, 7i,hd, 7i,he, 7i,hf, 5i,hh, 5i} — observe a associação entre tokens e pesos ht, w (t)i. Tem-se w (r) = 40, w (s) = 50, e w (r ∩ s) = 35. Seja sim a similaridade w(r∩s) 35 Jaccard. Portanto, sim (r, s) = w(r)∪w(s) = 40+50−35 ≈ 0.64. A seguir, as operações de seleção e junção por similaridade baseadas em conjuntos são definidas formalmente. maior, mas um IDF menor. O peso de um token t é denotado por w (t). O tamanho de um conjunto r, denotado por |r|, é a quantidade de tokens em r, e o peso de r, denotado por w (r), é o somatório dos pesos de seus tokens, isto é w (r) = ∑t∈r w (t). 3.3 Definition 1 (Seleção por Similaridade). Dada uma coleção de conjuntos CR , um conjunto s, uma função de similaridade sim e um limiar de corte τ no intervalo [0, 1], uma Seleção por Similaridade sobre CR usando s, denotado por SS (CR , s), retorna todos conjuntos valorados hr, τ0i, tal que r ∈ Cr e sim (r, s) = τ0 ≥ τ. Funções de Similaridade Uma função de similaridade tem o objetivo de quantificar o grau de semelhança entre os objetos de um banco de dados. Dois atributos são comparados e, normalmente um valor entre 0 e 1 é retornado, sendo que quanto maior o valor, maior o grau de similaridade. Com isso, são selecionadas para análise posterior as palavras que possuem uma semelhança maior ou igual a um limite (threshold), geralmente um valor entre 0 e 1, que é fornecido pelo usuário (Koudas et al., 2004; Gravano et al., 2003). Existe uma variedade de funções de similaridade na literatura, entre as mais populares estão o Cosseno, Dice e Jaccard (Cohen, 1998). Além disso, existe uma outra classe de funções que calculam o grau de diferença entre dois objetos, mas que podem ser facilmente adaptadas para uso em operações de similaridade. A Distância de Edição (Navarro, 2001) é uma representante popular dessa classe. No restante do artigo, o termo função de similaridade será usado para se referir a funções de ambas as classes. Exemplo 2. Considere a coleção de conjuntos CR = (r ={hc, 9i,hb, 7i,hd, 7i,he, 7i,hh, 5i,hi, 5i} e t ={ha, 10i,hc, 9i,hb, 7i,hd, 7i,he, 7i,hf, 5i,hh, 5i} ) e o conjunto s ={ha, 10i,hc, 9i,hb, 7i,hd, 7i,he, 7i,hj, 5i} — observe a associação entre tokens e pesos ht, w (t)i. Tem-se w (r) = 40, w (t) = 50, w (s) = 45, w (r ∩ s) = 30, w (t ∩ s) = 40 e um τ = 0.7. Seja sim a simiw(r∩s) laridade Jaccard. Portanto, sim (r, s) = w(r)∪w(s) = 3.4 Exemplo 3. Considere a coleção de conjuntos CR = (r ={hc, 9i,hb, 7i,hd, 7i,he, 7i,hh, 5i,hi, 5i} e t ={ha, 10i,hc, 9i,hb, 7i,hd, 7i,he, 7i,hf, 5i,hh, 5i} ) e a coleção de conjuntos Cs = (s ={ha, 10i,hc, 9i,hb, 7i,hd, 7i,he, 7i,hj, 5i} e u ={hc, 9i,hb, 7i,hd, 7i,he, 7i,hh, 5i,hk, 3i} ) — observe a associação entre tokens e pesos ht, w (t)i. Tem-se w (r) = 40, w (t) = 50, w (s) = 45, w (u) = 38, w (r ∩ s) = 30, w (r ∩ u) = 35, w (t ∩ s) = 40, w (t ∩ u) = 35 e um τ = 0.7. Seja sim a similaridade Jaccard. Portanto, sim (r, s) = w(r∩s) w(r∩u) 30 w(r)∪w(s) = 40+45−30 ≈ 0.54, sim (r, u) = w(r)∪w(u) = w(t∩s) 40 ≈ 0.54 e sim (t, s) = w(t)∪w(s) = 50+45−40 ≈ 0.72. Neste caso apenas o conjunto (t, s) seria retornado pela seleção, pois o valor de similaridade é maior que o limiar de corte. 30 40+45−30 Definition 2 (Junção por Similaridade). Dadas duas coleções de conjuntos CR e CS , uma função de similaridade sim e um limiar de corte τ no intervalo [0, 1], a Junção por Similaridade entre CR e CS , denotada por JS (CR , CS ), retorna todos os pares de conjuntos valorados h(r, s), τ0i tal que (r, s) ∈ Cr × Cs e sim (r, s) = τ0 ≥ τ. Funções de Similaridade baseadas em Conjuntos Neste trabalho, é considerada uma família de funções de similaridade baseadas em conjuntos (ou simplesmente função de similaridade, por brevidade). Dados dois conjuntos r e s, uma função de similaridade baseada em conjuntos sim (r, s) retorna um valor entre [0, 1] para representar a similaridade desses conjuntos; um valor maior indica que r e s possuem maior similaridade. As definições das funções Jaccard, Dice e Cosseno (Sarawagi and Kirpal, 2004; Bayardo et al., 35 40+38−35 13 ≈ 0.81, sim (t, s) = w(t∩s) w(t)∪w(s) = 40 50+45−40 ≈ Tabela 2: Filtros baseados em tamanho w(t∩u) 35 0.72 e sim (t, u) = w(t)∪w(u) = 50+38−35 ≈ 0.66. Neste caso os conjuntos (t, s) e (r, u) seriam retornados pela junção, pois o valor de similaridade é maior que o limiar de corte. É importante observar que todas as funções de similaridade consideradas medem a interseção entre dois conjuntos para derivar um valor de similaridade. Como resultado, predicados do tipo sim (r, s) >= τ, onde τ é limiar de corte entre [0, 1], podem ser representados de maneira equivalente em termos de um limite de interseção. Mais formalmente, dados dois conjuntos r e s, uma função de similaridade sim e um limiar de corte τ, o limite de interseção entre r e s para sim, denotado por intersec (r, s), é uma função que mapeia τ e os pesos de r e s para um valor real tal que sim (r, s) ≥ τ iff w (r ∩ s) ≥ intersec (r, s). Tabela 1 mostra o limite de interseção das funções de similaridade apresentadas anteriormente. Agora, operações de similaridade podem ser reduzidas ao problema de encontrar pares de conjuntos r e s cuja interseção não é menor que intersec (r, s). 3.5 [minsize(r),maxsize(r)] Jaccard [τ · |r|, |r| τ] Dice (2−τ)·|r| ] [ τ·|r| 2·τ , τ Cosseno ] [τ · |r|, |x| τ2 rações de edição (Gravano et al., 2001). Definition 4 (Distância de Edição). A distância de edição entre duas strings é o número mínimo de operações de edição (isto é, inserções, exclusões e substituições) dos caracteres individuais necessários para transformar a primeira string na segunda. Neste trabalho foi utilizada uma variante da distância de edição, baseada em custo unitário para todas operações de edição. Por exemplo, considere uma string σ1 = tokens e uma string σ2 = token. A distância de edição entre elas é igual a 1, pois é necessário apenas excluir o caractere ’s’ da primeira string para que as duas sejam iguais. A função executa uma junção entre duas tabelas bases e retorna apenas os pares de tuplas que possuem uma distância de edição menor ou igual a uma variável definida como k (Gravano et al., 2001). Filtros baseados em Tamanho O limite de interseção entre dois conjuntos r e s em relação à função de similaridade, denotado por intersec(r, s) foi especificado com maiores detalhes na Seção 3.4. Onde pode-se descartar todos os pares onde a interseção é menor do que intersec(r, s). Com essa definição de interseção é possível formular limites de tamanho para estes conjuntos. Explorando a definição das funções de similaridade apresentadas na Tabela 1. Derivando limites mais rígidos que permitem a poda imediata de pares de candidatos cujos tamanhos diferem bastante. Os limites de tamanho do conjunto r em relação a similaridade são as funções minsize(r) e maxsize(r) (Ribeiro and Härder, 2011). Definition 5 (Junção baseada em Distância de Edição). Dada duas tabelas A e B, com atributos textuais A.Ai e B.Bi e um inteiro positivo k, a junção recupera todos os pares de tuplas (t,t 0 ) ∈ AxB, tal que edit_distance(A.Ai(t), B.Bi(t 0 )) ≤ k A função pode executar uma seleção em uma tabela base, neste caso são retornadas apenas as tuplas que possuem uma distância de edição menor ou igual a k. Definition 3 (Filtro de Tamanho). Dado um conjunto r, uma função de similaridade Sim e um threshold τ. O filtro por tamanho de r relativo a Sim, denotado por minsize(r) e maxsize(r), mapeiam o τ e o tamanho de r a um valor real ∀ s. Se a similaridade(r, s) >= τ então minsize(r) ≤ |s| ≤ maxsize(r). Neste caso podese ignorar todos os conjuntos cujo tamanho não caem dentro do intervalo [minsize(r), maxsize(r)]. Definition 6 (Seleção baseada em Distância de Edição). Dada uma tabela A, com atributo textual A.Ai, uma string σ para a seleção e um inteiro positivo k, a seleção recupera todas as tuplas t ∈ A, tal que edit_distance(σ, A.Ai(t)) ≤ k Uma forma de melhorar o desempenho da junção é através da utilizaçao das propriedades dos q-grams. O objetivo principal neste caso é identificar eficientemente os candidatos do problema. Neste caso são utilizados dois filtros: tamanho e contagem. A ideia básica do filtro por contagem é aproveitar a informação transmitida pelos conjuntos dos tokens das strings para determinar se elas estão dentro de uma distância de edição k. A intuição aqui é que Estes limites podem ser observados na Tabela 2. 3.6 Função Função de Similaridade baseada em Distância de Edição A distância de edição é uma medida comum para medir a distância entre duas strings baseando-se em ope- 14 prefixo de s1 formado pelos seus dois primeiros elementos tem uma interseção não nula com o prefixo de s2, isto é, o subconjunto formado pelos dois primeiros elementos de s2. Portanto, em vez de calcular a interseção entre todos os elementos dos conjuntos originais, podemos inicialmennte ignorar um grande parte dos tokens e apenas verificar se existe alguma interseção nos prefixos. Pares de conjuntos cuja interseção dos prefixos for nula podem ser imediatamente descartados. Dessa maneira, é possível filtrar uma parte considerável do espaço de comparação usando apenas subconjuntos dos conjuntos originais. É importante ressaltar que a interseção entre prefixos é uma condição necessária, mas não suficiente para que dois conjuntos possuam uma determinada interseção. Ou seja, pares de conjuntos com interseção de prefixos diferente de vazio são considerados candidatos e devem ter sua interseção verificada em uma fase posterior. Uma questão relevante é a definição da ordem global dos tokens. Normalmente é utilizado a estatística DF de forma crescente (Chaudhuri et al., 2006) (relembrando, DF refere-se à frequência de cada token no banco de dados). A ideia é que, comos prefixos serão formados pelos tokens mais raros de cada conjunto, então o número de candidatos será reduzido. O princípio do prefix filtering pode ser estendido para conjuntos com pesos. Dado um conjunto r com peso, o prefixo(r) é um subconjunto correspondente ao prefixo mais curto cujo somatório seja maior que β. Sendo assim: as strings estão dentro de uma distância de edição pequena se elas partilham um grande número de tokens em comum. A seguir esta intuição será definida formalmente. Considere uma string σ1, e outra σ2, que é obtida pela substituição de um único caractere de σ1. Então os conjuntos q-grams Gσ1 e Gσ2, diferem por no máximo q (o comprimento de q-gram). Isto porque os q-grams que não se sobrepõem com o caractere substituído devem ser comuns aos dois conjuntos, e há apenas q q-grams que se sobrepõe ao caractere substituído. Uma observação semelhante vale para inserções e exclusões de um único caractere. Em outras palavras, σ1 e σ2 tem de ter pelo menos (max(|σ1|, |σ2|) + q − 1) − q = max(|σ1|, |σ2|) − 1 qgrams em comum. Quando a distância de edição de σ1, e σ2 é k, o limite inferior do número correspondentes de q-grams é (Gravano et al., 2001): Definition 7 (Filtro por contagem). Considere as string σ1, e σ2 de comprimento |σ1| e |σ2| respectivamente. Se σ1 e σ2 estão a uma distância de edição k, então a cardinalidade de Gσ1 ∩ Gσ2, ignorandose a informação posicional, deve ser de pelo menos max(|σ1|, |σ2|) − 1 − (k − 1) · q. O filtro por tamanho possui uma ideia simples: o tamanho da string fornece informações úteis para rapidamente descartar strings que não estão dentro da distância de edição desejada. Definition 8 (Filtro por tamanho). Duas strings σ1 e σ2 estão dentro de uma distância de edição k, se seus comprimentos não diferem em mais de k. 3.7 Definition 10 (Prefix Filtering com Peso). Considere dois conjuntos s1 e s2 com pesos, de modo que wt(s1 ∩ s2) ≥ α. Se β1 = wt(s1) − α e β2 = / wt(s2) − α, então o prefixo β1(s1) ∩ β2(s2) 6= 0. Prefix Filtering A intuição do prefix filtering é que quando dois conjuntos tem uma determinada interseção, então também deve existir alguma interseção entre subconjuntos ordenados de acordo com um determinada ordem global. Para concretizar a intuição considere o caso em que todos os conjuntos não possuem peso e tem um tamanho fixo h (Chaudhuri et al., 2006). Com isso, pode-se observar a seguinte propriedade: 3.8 Design Pattern e Data Mapper Pattern Design Pattern descreve uma solução reutilizável para um problema frequente no desenvolvimento de sistemas orientados a objeto. Um design pattern não é um código final, mas uma descrição de como resolver determinado problema. Podendo assim ser usado em situações diferentes que envolvam o mesmo problema. Normalmente o Design Pattern define as relações e as interações entre as classes e os objetos envolvidos. Os objetos e o banco de dados têm diferentes maneiras de estruturar os dados, que não combinam entre si. É necessário transferir os dados entre os dois esquemas, e essas transferências são de extrema complexidade. O Data Mapper é uma camada de software que separa os objetos e o banco de dados. A sua responsa- Definition 9 (Princípio Prefix Filtering). Sendo s1 e s2 dois conjuntos de tamanho h, ordenados segundo uma determinada ordem global. Considere r1 um subconjunto formado pelos primeiros h − k + 1 elementos de s1. Similarmente, considere um conjunto / r2. Se |s1 ∩ s2| ≥ k então |r1 ∩ r2| 6= 0. Por exemplo, considere os conjuntos ordenados segundo uma determinada ordem global s1 = {1,2,3,4,5} e s2 = {1,3,4,5,6}. É possível observar que s1 e s2 possuem uma interseção de 4. O chamado 15 de estatísticas. O conceito já foi explicado com maiores detalhes na Seção 3.8. Para a criação de um objeto SimDataMapper, primeiramente é necessária a escolha de um atributo textual para suporte a operações de similaridade. Este objeto passa a intermediar operações CRUD subsequentes. A operação create envolve a criação das tabelas auxiliares, que estão divididas em quatro estágios diferentes. A relação de tabelas criadas em cada estágio é especificado na Tabela 3. As tabelas até o Estágio 1 são chamdadas tabelas “Base”, ao passo que as tabelas nos demais estágios podem ser interpretadas como tabelas de indíces (do inglês index tables). Não é necessário a criação das tabelas de todos os estágios, esta escolha depende do tipo de aplicação sobre a qual o padrão arquitetural será implantado. Mais especificamente, o estágio adequado depende da característica da carga de trabalho imposta pela aplicação ao SGBD, em particular, da proporção entre operações de leitura e escrita. Os estágios superiores propiciam consultas mais rápidas, mas a atualização é mais onerosa; para os estágios inferiores é o inverso: consultas são mais custosas e atualização é mais rápida. Por exemplo, se o banco de dados alvo possui um maior número de operações de atualização (inserção, exclusão ou modificação) do que consultas, pode ser interessante manter as tabelas apenas até o estágio 2. Caso o banco de dados possua um maior número de consultas do que operações de edição, o interessante é manter todas as tabelas, ou seja, dos 4 estágios (Koudas et al., 2007). Neste trabalho, iremos apenas considerar consultas a partir do estágio 2. Detalhes sobre a criação das tabelas serão apresentados na Seção 5. Figura 3 apresenta o diagrama de sequência da operação que constrói um objeto SimDataMapper. Após a criação, o objeto SimDataMapper recebe a invocação do método de instalação com diversos parâmetros: a tabela, o identificador e o atributo sobre os quais o suporte para similaridade será instalado; paramêtro para o algoritmo de geração de tokens, isto é, o tamanho de q e o estágio definindo as tabelas auxiliares a serem criadas. O conjunto de strings associadas com o atributo selecionado são copiadas para um ResultSet que é posteriormente lido para geração de tokens e população da tabela BaseTokens. As demais tabelas auxiliares são criadas em seguida, baseado no estágio informado. A operação delete tem a função de excluir as tabelas auxiliares quando for solicitado, nos estágios informados. Em operações retrieve ocorre a conversão em uma seleção por similaridade (caso a condição da seleção envolva um atributo que tenha sido escolhido para su- bilidade é a transferência de dados entre esses mecanismos, mantendo-os isolados um do outro. Ou seja, não é necessário o conhecimento sobre o esquema do banco de dados e nem de interface SQL. A principal função de um Data Mapper é a separação do domínio e a fonte de dados. O Data Mapper Pattern é um padrão baseado no CRUD (Create, Retrieve, Update, Delete) (Fowler, 2002). O CRUD define as operações básicas no contexto de banco de dados, elas operam em objetos que representam entidades. 4 SIMDATAMAPPER Esta seção descreve o padrão arquitetural SimDataMapper, que permite que aplicações executem operações de similaridade sobre SGBDs de maneira transparente e flexível. Com isso, o SimDataMapper permite que aplicações incorporem operações de similaridade com pouco esforço de desenvolvimento. O SimDataMapper suporta todas as funções e operações de similaridade discutidas anteriormente. A Figura 2 ilustra a organização do SimDataMapper. Figura 2: SimDataMapper O componente central é a camada representada pelo SimDataMapper, um padrão arquitetural baseado no conceito de Data Mappers (Fowler, 2002). Assim como qualquer Data Mapper, o SimDataMapper é uma camada de software que separa objetos em memória de detalhes a respeito do acesso ao banco de dados. Diferentemente de Data Mappers comuns, o SimDataMapper também isola os detalhes de aplicações sobre o processamento de operações de similaridade, encapsulando e gerenciando todo o suporte a essas operações. Incluindo criação e manutenção de tabelas auxiliares, execução de consultas de acordo com a noção de similaridade escolhida e propagação 16 prover de maneira flexível diferentes noções de similaridade. Este fato é de particular importância porque é amplamente reconhecida a inexistência de uma função de similaridade que seja a melhor em todos os cenários (Cohen et al., 2003). Figura 3: Diagrama de sequência da operação que constrói o suporte a operações de similaridade Tabela 3: Relação de tabelas por estágios Estágio 1 2 Figura 4: Diagrama de sequência da operação Retrieve Tabela(s) Finalmente, as operações de edição são executadas pela aplicação da operação update, ela é descrita no diagrama de sequência ilustrado na Figura 5. Primeiramente, é feita uma consulta para verificar se o limite de operações já foi atingido. Se for o caso, o mapeamento contendo o conjunto de operações pendentes para cada string é acessado e processado, e as modificações são propagadas para as tabelas auxiliares. Dependendo do estágio de propagação selecionado. BaseTokens, BaseDF, BaseSize BaseRawWeights, BaseRawLenght 3 BaseLenght 4 BaseWeights portar operações por similaridade). Neste caso a seleção depende do tipo de função escolhida (Jaccard, Dice, Cosseno) e do(s) estágio(s) envolvido(s). A execução da operação depende de dois parâmetros, são eles: a string a ser pesquisada e o threshold. A operação update envolve as operações de edição, neste caso elas são sempre intermediadas pelo objeto SimDataMapper e envolve a estratégia de propagação de estatísticas. Para isso é necessário informar a quantidade necessária de operações de edição para disparar a propagação. Neste caso é utilizada a estratégia de blocagem (Koudas et al., 2007), onde a propagação de estatísticas é postergada até um um certo número de operações de modificações identificado previamente. Atualmente as edições são realizadas com o auxílio de um arquivo texto. Em uma nova versão, as informações serão mantidas armazenadas no banco de dados. A operação de seleção por similaridade é ilustrada na Figura 4. A invocação da operação é repassada para o objeto SimDataMapper que realiza a seleção por similaridade através de chamadas JDBC. Como o conjunto de tabelas auxiliares é independente da função de similaridade, o objeto SimDataMapper pode Figura 5: Diagrama de sequência da operação Update 5 IMPLEMENTAÇÃO Esta seção apresenta detalhes sobre a implementação das funções de similaridade discutidas anteriormente em SGBDs. As operações de similaridade são 17 expressadas declarativamente em SQL. Uma observação importante neste contexto é que a maior parte das funções de similaridade são totalmente especificadas em SQL, sem o uso de UDFs. Este aspecto é importante porque a otimização de consultas envolvendo UDFs é notoriamente difícil (Chaudhuri and Shim, 1999). Neste cenário, a implementação das funções são divididas entre as que são baseadas em conjuntos, descritas na Seção 5.1 e a função baseada em distância de edição, descrita na Seção 5.2. 5.1 mero de operações é identificado por uma constante definida como batch. Portanto, se o batch for igual a 100, o arquivo possui 100 operações divididas entre inserções, exclusões e modificações e as tabelas afetadas dependem do estágio definido. Para isso, os valores do DF são obtidos da seguinte maneira: INSERT INTO BaseDF(tok, DF) SELECT T.tok, COUNT(T.tid) FROM BaseTokens T GROUP BY T.tok Implementação das Funções de Similaridade baseadas em Conjuntos Para cada token distinto presente na tabela BaseTokens é realizado uma contagem para identificar a frequência dos tokens na tabela base. Completando a criação de tabelas do Estágio 1 é necessário criar a tabela size, ela armazena apenas um campo que contêm a quantidade de registros da tabela base. A seguir são apresentados os comandos para sua criação: A implementação das funções baseadas em conjuntos utiliza as tabelas auxiliares dos quatro estágios descritas anteriormente na Seção 4. O primeiro passo é a escolha de um atributo textual de uma tabela para suportar seleções e junções por similaridade. Para isso é necessário inicialmente a criação de uma tabela de q-gram tokens: BaseTokens(tid, tok), onde tid é a chave primária da tabela original e tok armazena os tokens para cada string. Os tokens são criados utilizando os delimitadores no início e no fim e o conceito de bag, apresentados na Seção 3.1. O q utilizado foi igual a 3, pois observando-se trabalhos anteriores (Gravano et al., 2001) é o valor que apresenta melhor resultado. Os pesos IDF associados com cada token são armazenados em uma outra tabela auxiliar. Neste ponto, surgem questões à respeito da atualização dos pesos após modificações no banco de dados. Praticamente toda alteração causará modificação da estatística DF e portanto o peso IDF de todos tokens envolvidos terá que ser atualizado, pois depende diretamente do número de tuplas da tabela base. Claramente, este requisito pode ter um impacto negativo de desempenho. Mais problemático ainda são inserções e exclusões, que alteram a quantidade de strings consideradas N, e resultam na atualização do peso IDF de todos os tokens. Uma maneira direta de mitigar o problema da atualização das estatísticas é usar uma estratégia de propagação de estatística. Neste caso os IDFs alterados nas tabelas do estágio 2 serão apenas os que estão relacionados aos tokens que sofreram esta mudança. Já as tabelas do estágio 3 e 4 terão que ser reconstruídas totalmente, pois dependem diretamente da quantidade de strings armazenadas na tabela base. No trabalho, a estratégia de blocagem utilizada foi baseada em um arquivo texto, ou seja, um arquivo possui certo número de operações de edição que são executadas dependendo do estágio informado. O nú- INSERT INTO BaseSize(size) SELECT COUNT(*) FROM Base Para lidar com alterações na quantidade de strings, é necessário isolar o valor de N no cálculo do peso dos conjuntos. Seja r um conjunto de tokens e df (t) a estatística DF de um token t, o cálculo do peso pode ser representado da seguinte forma: w (r) = ∑ w (t) t∈r = ∑ log (N) − log (df (t)) t∈r = log (N) ∑ 1 − ∑ −log (df (t)) t∈r t∈r = log (N) · |r| − ∑ log (df (t)) . t∈r Dessa maneira, é possivel armazenar os fatores s1 = |r| e s2 = ∑t∈r log (df (t)) para cada string: INSERT INTO BaseRawLength( SELECT t.tid, COUNT(*) as s1, SUM(log(d.DF)) as s2 FROM BaseTokens t, BaseDF d WHERE t.tok = d.tok GROUP BY t.tid) O fator s1 armazena a quantidade de tokens que a string possui e s2 armazena o somatório dos logaritmos dos DFs, ou seja, o somatório dos pesos dos tokens da string. 18 Além da tabela apresentada anteriormente, é necessário manter outra para completar o conjunto de tabelas auxiliares pertencentes ao Estágio 2. Essa tabela tem por objetivo associar strings, tokens e estatísticas DF: Observando as consultas das funções é possível verificar que o cálculo da similaridade é um pouco mais complexo. Pois ainda não existe o armazenamento dos pesos dos tokens e nem dos pesos dos conjuntos. Este cálculo é realizado em tempo de execução, o que faz com que o tempo de consulta aumente. Por isso, caso a carga do banco de dados seja caracterizada mais por consultas do que por inserções, pode ser vantajoso manter uma tabela com os pesos dos conjuntos de tokens associados com cada string, nesse caso é criada a tabela auxiliar do Estágio 3: INSERT INTO BaseRawWeights (SELECT t.tid, t.token, d.DF FROM BaseTokens t, BaseDF d WHERE t.tok = d.tok) Neste ponto, é possível realizar seleções por similaridade baseadas nas funções de similaridade Jaccard, Dice ou Cosseno. Dada uma string s usada na condição da seleção, uma tabela de tokens SearchToken(sid, token) é criada em tempo de execução, esta tabela possui apenas a finalidade de armazenar os tokens da string a ser pesquisada. Em seguida é criada a tabela com os pesos do conjunto de tokens de s, estes pesos são baseados nas estatísticas armazenas nas tabelas auxiliares BaseDF e BaseSize. INSERT INTO BaseLength( SELECT br.tid, (log(bs.size)*br.s1 - br.s2) FROM BaseRawLength br, BaseSize bs) Com isso é possível realizar novas seleções utilizando a tabela BaseLength. Definindo assim o processamento de consultas para o Estágio 3. A seguir será apresentada a consulta para a função Jaccard, as consultas paras as funções Dice e Cosseno estão no Apêndice A, considere t como threshold. INSERT INTO SearchLength( SELECT s.sid, SUM(log(b.size/df.df)) FROM SearchToken s,BaseSize b,BaseDF df WHERE s.tok = df.tok GROUP BY s.sid) [Jaccard] SELECT br.tid, SUM(log(bs.size/br.df))/ (bl.len + sl.len - SUM( log(bs.size/br.df))) as JACCARD FROM BaseLength bl, BaseSize bs, BaseRawWeights br, SearchToken st, SearchLength sl WHERE br.tok = st.tok AND st.sid = sl.sid AND bl.tid = br.tid AND bl.len >= t * sl.len AND bl.len <= bl.len / t GROUP BY st.sid, br.tid, bl.len, sl.len HAVING SUM(log(bs.size/br.df)) >= (t/(1+t)) * (bl.len + sl.len) A consulta abaixo define o processamento da consulta de seleção para o Estágio 2 (o Estágio 1 seria operar diretamente sobre as tabelas BaseToken e BaseDF) para a função Jaccard, as consultas para as funções Dice e Cosseno estão no Apêndice A, considere t como threshold. [Jaccard] SELECT br.tid, SUM(log(bs.size/br.DF))/ ((log(bs.size)*brl.s1-brl.s2) + sl.len - SUM(log(bs.size/ br.df))) as JACCARD FROM BaseSize bs, BaseRawWeights br, BaseRawLength brl, SearchToken st, SearchLength sl WHERE br.tok = st.tok AND st.sid = sl.sid AND brl.tid = br.tid GROUP BY st.sid, br.tid, bs.size, brl.s1, brl.s2, sl.len HAVING SUM(log(bs.size/br.df)) >= (t/(1+t)) * ((log(bs.size)* brl.s1 - brl.s2) + sl.len) Com a nova tabela não é mais necessário calcular o peso dos tokens, pois estes já foram pré-processados e armazenados. Consequentemente ocorre à diminuição no tempo de execução da consulta. Finalmente, é possível armazenar o peso de cada token juntamente com o peso do conjunto. Diminuindo assim ainda mais o tempo de execução da consulta. Para isso é necessário criar a última das tabelas auxiliares, referente ao Estágio 4: INSERT into BaseWeights( SELECT bl.tid, br.tok, 19 porque é necessário associar o tamanho das duas tabelas bases e os pesos dos tokens das strings nas duas relações. A seguir serão apresentadas as criações das tabelas necessárias. Considere a junção das tabelas Base e Base2. Para associar o tamanho é necessário criar uma nova tabela size, contendo a quantidade de tuplas presentes nas duas bases. A nova tabela de DF contém a junção dos DFs das duas tabelas bases. Finalmente é necessário a criação de duas novas tabelas de pesos dos tokens, que são associadas uma a cada tabela base. log(bs.size/br.df), bl.len FROM BaseLength bl, BaseSize bs, BaseRawWeights br WHERE bl.tid = br.tid) Com ela é possível definir o processamento das últimas consultas de seleção, as pertencentes ao Estágio 4. As consultas paras as funções Dice e Cosseno estão no Apêndice A, considere t como threshold, [Jaccard] SELECT bw.tid, SUM(idf)/(bw.len + sl.len - SUM(idf)) as JACCARD FROM BaseWeights bw, SearchToken st, SearchLength sl WHERE bw.tok = st.tok AND st.sid = sl.sid AND bw.len >= t * sl.len AND bw.len <= bw.len / t GROUP BY st.sid, bw.tid, bw.len, sl.len HAVING SUM(idf) >= (t/(1+t)) * (bw.len + sl.len) [Junção DF] INSERT INTO BaseBase2DF(tok,df) SELECT tok, SUM(df) FROM (SELECT * FROM BaseDF union all SELECT * FROM Base2DF) as combDF GROUP BY tok) [Junção Size] INSERT INTO BaseBase2Size(size) (SELECT t1Size.count + t2Size.count as size FROM (SELECT COUNT(*) FROM Base) as t1Size(count), (SELECT COUNT(*) FROM Base2) as t2Size(count)) A implementação da atualização de estatística ocorre através da utilização de duas Stored Procedure, uma para inserção e outra para exclusão. Neste caso as consultas são realizadas de maneira declarativa e as atualizações de estatísticas são executadas de maneira procedural por questões de desempenho. Como já citado anteriormente, a propagação depende do estágio informado, por isso a Stored Procedure recebe o estágio como parâmetro. Além disso recebe um conjunto de tokens referentes a string que sofrerá a operação de edição. Se o estágio informado for o 2, apenas as strings que possuem os tokens que sofrerão alteração no peso serão atualizadas. As tabelas dos Estágios 3 e 4 serão reconstruídas totalmente, por isso uma outra estratégia foi definida. Neste caso se o tamanho do batch for igual a 100, 99 operações serão executas apenas até o estágio 2 e apenas a última operação de edição executará a Stored Procedure toda, fazendo com que assim as tabelas do Estágio 3 e 4 sejam reconstruídas apenas uma vez. Utilizando todas as tabelas auxiliares, podemos observar que as consultas se tornam mais simples porque os valores dos pesos já estão pré-processados e armazenados. Eliminando a necessidade de calculá-los em tempo de execução. Com a apresentação das seleções é possível iniciar a apresentação das junções. Nas funções baseadas em conjuntos, elas são implementadas no Estágio 3. Primeiramente é necessário criar tabelas especificas para serem utilizadas nas junções. Isso acontece [BaseSearchLenght] INSERT INTO BaseSearchLength( SELECT t.tid, SUM(log(b.size/df.df)) FROM BaseTokens t, BaseBase2Size b, BaseBase2DF df WHERE t.tok = df.tok GROUP BY t.tid) A tabela Base2SearchLenght(tid, len) é criada analogamente a BaseSearchLenght(tid,len) citada anteriomente. A diferença é que utiliza a tabela de tokens referente a Base2. Depois que as todas estas tabelas foram criadas, já é possível executar as junções por similaridade das funções Jaccard, Dice e Cosseno, considere t como o threshold. As consultas paras as funções Dice e Cosseno estão no Apêndice A. [Jaccard] SELECT bl1.tid, bl2.tid, SUM(log(bs.size/df.df))/ (bl1.len + bl2.len SUM(log(bs.size/df.df))) 20 as JACCARD FROM BaseSearchLength bl1, BaseTokens t1, Base2SearchLength bl2, Base2Tokens t2, BaseBase2Size bs, BaseBase2DF df WHERE df.tok = t1.tok AND df.tok = t2.tok AND t1.tid = bl1.tid AND t2.tid = bl2.tid AND bl1.len >= t * bl2.len AND bl1.len <= bl1.len / t GROUP BY bl1.tid, bl2.tid, bl1.len, bl2.len HAVING SUM(log(bs.size/df.df)) >= (t/(1+t)) * (bl1.len + bl2.len) Neste ponto é importante observar que os limites de interseção apresentados na Tabela 1 foram utilizados para as funções Jaccard, Dice e Cosseno em todas as seleções e junções apresentadas anteriormente. Estes limites foram implementados na cláusula HAVING das consultas. Uma observação importante é que a complexidade envolvida no cálculo de interseção também diminui em relação aos estágios. Pois também utilizam os valores dos pesos dos tokens que já estão armazenados. Nas seleções dos Estágios 3 e 4 e nas junções é possível verificar a utilização dos filtros apresentados na Tabela 2 para diminuir o conjunto de candidatos e consequentemente diminuir o tempo da consulta. Eles são implementados na cláusula WHERE em todas as consultas e são baseados no conceito de minsize e maxsize. 5.2 int n; int[][] distance; m <-- length(s1)+1; n <-- length(s2)+1; Para i=1 até m faça distance[i][1] <-- i-1; Fim Para j=1 até n faça distance[1][j] <-- j-1; Fim Para j=1 até n-1 faça Para i=1 até m-1 faça Se s1.substring(i)= s2.substring(j) então distance[i+1][j+1]<-distance[i][j]; Senão distance[i+1][j+1] <-minimo( ditance[i][j+1], distance[i+1][j]+1; distance[i][j]); Fim Fim Fim Return distance[m][n]; } Para executar a junção, é necessário utilizar duas tabelas bases e suas tabelas de tokens correspondentes. O código para a execução da função é apresentado a seguir. As tabelas bases são Base e Base2, o atributo textual habiltado para similaridade é o name, e o identificador é o id. A função utiliza dois tipos de filtros: tamanho e contagem. Apenas as tuplas que possuem uma distância de edição menor ou igual a k são retornadas nesta consulta e q é o tamanho dos q-grams (Gravano et al., 2001). Implementação da Função de Similaridade baseada na Distância de Edição Até agora a implementação apresentada trata apenas das funções por similaridade baseadas em conjuntos. A implementação da distância de edição é a mais simples das quatro funções que estão presentes neste trabalho. Ela trabalha apenas com a tabela de tokens e necessita de uma função para calcular a distância de edição entre duas strings. Esta função é criada baseada no algoritmo Levenshtein distance. No padrão SimDataMapper ela foi implementada como UDF. SELECT Base.id, Base2.id, Base.name, Base2.name FROM Base, BaseTokens, Base2, Base2Tokens WHERE Base.id = BaseTokens.tid AND Base2.id = Base2Tokens.tid AND BaseTokens.tok=Base2Tokens.tok AND ABS(character_length(Base.name) character_length(Base2.name)) <= k AND (character_length(Base.name)+ [Algoritmo Edit Distance] Algoritmo edit_distance(String s1, String s2, int k){ int m; 21 conjunto: q -1 > k * q OR character_length(Base2.name)+ q -1 > k * q ) GROUP BY Base.id, Base2.id, Base.name, Base2.name HAVING COUNT(*)>=char_length(Base.name) - 1 - (k-1)*q AND COUNT(*)>=char_length(Base2.name) - 1 - (k-1)*q AND edit_distance(Base.name, Base2.name,k) [Consulta Genérica Prefix Filtering] INSERT INTO BasePrefixTable (SELECT tid, tok FROM (SELECT br.tid, tok, len, (SUM(log(bs.size/br.df)) OVER (PARTITION BY br.tid ORDER BY br.df asc,tok) log(bs.size/br.df)) as partSum FROM BaseLength bl, BaseSize bs, BaseRawWeights br WHERE bl.tid = br.tid) as prefTmp WHERE partSum <= (filtro de tamanho) Observando o código, é possível verificar que o Filtro de Tamanho é realizado na condição da cláusula WHERE, na condição que verifica a diferença de tamanho das duas strings. O Filtro de Contagem, elimina os pares de atributos que possuem poucos tokens em comum, ele é executado pelas condições em COUNT(*) da cláusula HAVING. Algo particularmente interessante é que filtro por contagem e o filtro por tamanho, podem ser expressos naturalmente por uma expressão SQL no banco de dados. 5.3 As consultas se diferem apenas pela condição da cláusula WHERE, que define o filtro de tamanho. Neste caso para a função Jaccard a condição é definida como WHERE partSum <= len - (len * τ). A função Dice utiliza a condição como WHERE partSum <= len - ((len * τ)/(2 - τ)) e finalmente para função Cosseno a definição é WHERE partSum <= len - (len * τ * τ), sendo τ o threshold. A cláusula OVER é responsável por referenciar a janela que fará parte da agregação. Neste caso (SUM(log(bs.size/br.df)). A cláusula PARTITION BY determina a janela, ela agrupa as tuplas, fazendo com que todas do mesmo grupo, ou mesma partição receba o resultado da agregação, ou seja PARTITION BY br.tid ORDER BY br.df asc,tok) log(bs.size/br.df)) as partSum. Na distância de edição, a criação é parecida, mas utiliza uma funcionalidade a mais, além das cláusulas OVER e PARTITION BY é utilizada a cláusula RANK que realiza a ordenação dos resultados por partição. Implementação do Prefix Filtering A implementação do prefix filtering exige a criação de mais duas tabelas BasePrefixTable(tid, tok) e Base2PrefixTable(tid, tok), uma tabela de prefixo para cada tabela base envolvida na junção. A definição dos tokens pertencentes ao prefixo para as funções baseadas em conjunto é diferente para cada função. Pois se baseiam nos filtros de tamanho apresentados na Tabela 2. Para definir o Prefix Filtering para a distância de edição é utilizada pela primeira vez para esta função a informação dos DFs dos tokens, e para definir o limite são utilizadas as variáveis k e q. Para auxiliar na criação do prefixo foram utilizadas Windows Functions (PostgreSQL, 2014), elas são capazes de realizar cálculos em uma linha com dados presentes em linhas relacionadas a ela. Neste caso um grupo de linhas correlacionadas é considerada uma janela. Window Function foram adicionadas na especificação do SQL em 2003, e hoje são suportadas por boa parte dos principais SGBDs, entre eles PostgreSQL, DB2 e Oracle. É importante ressaltar que neste trabalho, o prefix filtering foi implementado de forma declarativa, diferenciando-se da maioria dos trabalhos anteriores que implementaram o prefix filtering via UDFs (Chaudhuri et al., 2006). A seguir será apresentada uma consulta genérica para a criação do prefixo para as funções baseadas em [Distância de edição] INSERT INTO BasePrefixTableED SELECT tid, tok FROM (SELECT bt.tid, bt.tok, rank() OVER (PARTITION BY bt.tid ORDER BY bd.df asc, bt.tok) as rank FROM BaseTokens bt, BaseDF bd, Base WHERE bt.tok = bd.tok AND bt.tid = Base.id) as pref WHERE rank <= q*k+1 Depois que as tabelas foram criadas já é possível executar as junções com a utilização do Prefix Filtering. Neste caso as consultas serão muito parecidas com as apresentação na Seção 5.1 e 5.2. Mas será 22 acrescentado na cláusula FROM a geração dos candidatos a participarem da junção. É verificado se duas tuplas possuem pelo menos um token em comum no prefix filtering: A distância de edição estende apenas o Stage1, pois utiliza apenas as tabelas BaseTokens e BaseDF, como a função é apenas habilitada a junção por similaridade, sua função retrieve implementa esta funcionalidade. A tabela de DF é utilizada para a criação do Prefix Filtering. [Seleção de Candidatos] (SELECT DISTINCT p1.tid as tid1, p2.tid as tid2 FROM BasePrefixTable p1, Base2PrefixTable p2 WHERE p1.tok = p2.tok) as CANDIDATOS 6 Nesta seção serão apresentados os experimentos e as conclusões envolvidas na análise dos mesmos. Para a execução dos experimentos foram utilizadas algumas ferramentas no desenvolvimento. A linguagem utilizada foi Java, que é uma linguagem orientada a objetos. O banco de dados foi o PostgreSQL, que oferece inúmeros recursos e suporta uma grande parte do padrão SQL. Para conexão da linguagem Java com o banco de dados foi utilizado o driver JDBC 9.3. JDBC é uma API do núcleo do Java que fornece um conjunto padrão de interfaces para bancos de dados SQL. O hardware utilizado foi um processador Intel Core I5 - 4200U CPU @ 1.60 GHz com 6.00 GB de memória RAM. E na clásula WHERE é acrescentada a condição CANDIDATOS.tid1=t1.tid And CANDIDATOS.tid2=t2.tid. 5.4 EXPERIMENTOS Implementação SimDataMapper A Figura 6 apresenta a estrutura das classes desenvolvidas baseadas no padrão arquitetural. É possível observar que existe uma interface SimDataMapper que se baseia no CRUD. A classe AbstractSimDataMapper implementa a interface SimDataMapper, implementando os componentes comuns a todos os estágios, por exemplo, a Stored Procedure de atualização de estatísticas. Os 4 estágios são representados por 4 classes diferentes, uma representando cada um. Elas estendem a classe abstrata apresentada anteriormente. Cada uma é responsável por criar e excluir as tabelas auxiliares envolvidas em cada estágio em particular. Estas operações são implementadas nos métodos create e delete. Nesse conjunto de classes a operação retrieve é implementada apenas no Stage1, pois é o único que é comum a todas as funções de similaridade baseadas em conjuntos. Neste caso, ela é responsável por criar as tabelas SearchToken e SearchLength . A operação update é responsável pela propagação de estatística. Neste caso é verificado o tipo de edição (inserção, deleção e modificação). Também verifica se é viável a edição no banco de dados, por exemplo, se realmente existe a string a ser excluída e invoca a Stored Procedure dependendo do estágio. O Stage3 é responsável pela construção das tabelas de prefixo, dependendo do tipo de função selecionada. As 4 classes dos estágios são estendidas para implementar os estágios diferentes das funções Jaccard, Dice e Cosseno. Neste caso a operação retrieve é implementada dependendo da função e do estágio envolvido, elas são utilizadas com chamadas JDBC. O estágio 3 de cada uma dessas funções também é responsável por implementar a junção por similaridade com e sem prefixo. 6.1 Dados Os dados utilizados são os do banco de dados online IMDB (Internet Movie Database). Que possui informações de atores, personagens fictícios, entre outras informações de filmes, seriados, programas de televisão e video-games. A tabela utilizada como base será a name, que contêm nome de atrizes e atores. Amostras são geradas a partir desta tabela name. Os experimentos serão realizados com duas tabelas geradas a partir do banco IMDB, as duas contendo 20 mil tuplas. Sendo que a primeira foi criada como uma amostra da tabela name e a segunda foi gerada utilizando a primeira com erros aleatórios inseridos propositalmente. Esse procedimento de “sujar” os dados é realizado com o auxílio de uma função implementada em Java. 6.2 Seleções por Similaridade Inicialmente as tabelas auxiliares apresentadas na Tabela 3 foram criadas utilizando a tabela base do banco de dados IMDB com 20 mil tuplas. Os tempos envolvidos na criação estão na Tabela 4 e estão divididos por estágios. É importante observar que o tamanho de q-gram utilizado foi 3. Os experimentos de seleção foram realizados nos 4 estágios das funções Jaccard, Dice e Cosseno. O Estágio 1 realiza apenas a criação das tabelas 23 Figura 6: Digrama de classe SimDataMapper Tabela 4: Tempo de criação das tabelas auxiliares Estágio Tempo (segundos) 1 47,984 2 8,126 3 0,274 4 3,838 Figura 7: Gráfico das seleções do Estágio 2 envolvidas na seleção, neste caso SearchToken e SearchLenght. Para realizar a operação de seleção é necessário informar uma string e um threshold para a busca. Neste caso foram realizadas 20 seleções para cada função de similaridade. Após as execuções foi calculada uma média dos tempos de execução. As strings foram selecionadas aleatoriamente na base de dados. O threshold utilizado foi de 0.7. Nas Figuras 7, 8 e 9 observam-se três gráficos referentes aos tempos de seleção. Existe um gráfico para cada estágio e em cada gráfico é possível observar o tempo referente a cada função de similaridade baseada em conjunto. O tempo do Estágio 1 é igual para as três funções, pois são criadas as mesmas tabelas informadas anteriormente. Neste caso o tempo foi de 0,078 segundos. Observando o Estágio 2 pode-se verificar que os tempos de seleção estão próximos, eles divergem em poucos segundos, mas a função Dice se sobressai em Figura 8: Gráfico das seleções do Estágio 3 relação as outras duas. Nos Estágios 3 e 4 os tempos de busca caem abruptamente, isso se deve a dois fatores: o cálculo menos complexo da similaridade, que diminui con- 24 gura 10, analisando é possível verificar que a Distância de Edição apresentou o melhor desempenho. Isto se deve ao fato de que os seus filtros apresentaram melhor desempenho para este conjunto de dados. Dos 400.000.000 pares de tuplas possíveis na junção, apenas 117.238 foram verificadas pelo algoritmo de distância de edição, os outros foram descartados pelos dois filtros presentes na consulta. Entre as funções baseadas em conjuntos a que apresentou melhor desempenho foi a Jaccard. Este desempenho também se deve ao fato dos filtros serem mais efetivos, neste caso 59.942.451 pares de tuplas foram analisados pela função, os outros foram descartados. A função Dice analisou 77.255.206 pares de tuplas e a função Cosseno analisou 79.490.280 pares de tuplas. Com isso é possível observar que os filtros novamente foram efetivos, pois no mínimo conseguiu filtrar 80% dos candidatos. Figura 9: Gráfico das seleções do Estágio 4 forme aumenta o número dos estágios, ou seja, a consulta envolvida no Estágio 2 é mais complexa que a envolvida no Estágio 3. Mas principalmente isto se deve o fato da utilização dos filtros baseados no conceito de minsize e maxsize, que foi apresentado na Tabela 2, que é possível apenas nestes dois estágios. No Estágio 3 as consultas se comportam de maneira diferente do 2, neste caso a função que apresenta melhor desempenho é a Cosseno, seguida da Dice e depois pela Jaccard, elas também diferem em poucos segundos. O estágio 4 apresenta novamente uma variação do comportamento das funções, neste caso a que apresentou melhor desempenho foi novamente a Cosseno, porém ela foi seguida pela função Jaccard e por último a Dice. Neste caso podemos concluir que a utilização dos filtros é de extrema importância para a execução das seleções por similaridade de uma forma mais eficiente e que para este conjunto de dados a função Cosseno é a melhor escolha. 6.3 Figura 10: Gráfico das Junções 6.4 Junções por Similaridade Prefix Filtering Para a utilização do Prefix Filtering é necessário utilizar as mesmas tabelas de associação de DFs e tamanho criadas para executar a junção. Além disso, foram criadas as tabelas de prefixo para cada função de similaridade utilizando as mesmas tabelas bases envolvidas na junção anterior. Na Figura 11 pode-se observar que os tempos para criar as duas tabelas de prefixo variam pouco entre as funções de similaridade. A que apresenta menor tempo é à distância de edição e a de maior tempo é a função Dice. Os tempos da junção utilizando o prefixo são apresentados na Figura 12. Comparando o tempo de junção com a utilização do prefixo e sem a utilização é visível a diminuição drástica do tempo de execução da consulta.Isto pode ser verificado na Figura 13, onde é possível observar a diferença entre os tempos de exe- A operação de junção foi realizada para as quatro funções: Distância de edição, Jaccard, Dice e Cosseno. Foi utilizada a mesma tabela base utilizada nas seleções e as tabelas auxiliares que foram criadas. Neste caso também foi utilizada a tabela “suja”, com erros inseridos aleatoriamente, e suas tabelas auxiliares correspondentes. Primeiramente foi necessário criar as tabelas auxiliares que englobam os DFs e tamanhos das duas tabelas bases para as funções baseadas em conjunto, que foi apresentado na Seção 5.1. O tempo para a criação desse conjunto de tabelas foi de 7,951 segundos. Na distância de edição foi utilizado k=3. E nas funções baseadas em conjunto foi utilizado um threshold de 0.7. Os tempos de junção podem ser verificados na Fi- 25 Verificando a quantidade de pares de candidatos que foram descartados pelo prefixo podemos entender a diferença no tempo de execução quando não é utilizado o prefixo. Dos 400.000.000 pares de candidatos, apenas 1.351.357 pares foram avaliados pela função Dice, 1.937.080 pares pela função Cosseno, 1.157.306 pares pela função Jaccard e finalmente 46.202 pares pela função Distância de Edição. Como resultado direto da redução drástica do número de candidatos, o tempo de execução de todas funções é agora substancialmente menor. A função Dice agora é 74x mais rápida, a função Cosseno é 115x mais rápida, a função Jaccard é 40x mais rápida e a distância de edição é 2x mais rápida. A distância de edição ainda produz um número menor de candidatos em comparação com as demais funções, entrentato, a diferença agora é bem menor. Por exemplo, enquanto que sem o emprego do prefix filtering a quantidade de candidatos para a distância de edição é aproximadamente 511x menor do que para Jaccard, usando o prefixo esta proporção cai para 25x. Com isso, a maior complexidade da UDF usada para calcular a distância passa a representar o fator preponderante. De fato, o tempo de execução para a distância de edição é agora significativa maior em comparação com as demais funções de similaridade. Um fato interessante é que agora a função Jaccard, mesmo apresentando um número menor de candidatos, é (moderadamente) mais lenta que as funções Dice e Cosseno. Ainda não foi possível identificar o motivo preciso deste resultado. Pode-se concluir que a utilização do prefixo é de extrema importância para uma junção rápida quando estão envolvidos muitos pares de candidatos. O ganho de desempenho é evidente. Figura 11: Criação das tabelas de prefixo cução das junções com e sem prefixo. Isso demonstra como a abordagem utilizando o Prefix Filtering diminui notoriamente os pares de candidatos. Figura 12: Tempo de execução da junção com Prefix Filtering 6.5 Atualizações de estatísticas Os experimentos da propagação de estatísticas foram realizados com batches de 1, 10 e 100 tuplas. Ou seja, utilizando a técnica de blocagem, onde as operações de edição são postergadas até um número prédefinido de operações. Neste caso os batches representam o número de operações que serão armazenadas. Quando este número for atingido, a propagação é iniciada e são executadas todas as operações pendentes. Neste trabalho, com a ajuda de uma classe em Java, foi criado um arquivo auxiliar para gerar as operações de edição, para isto foram utilizadas as seguintes regras: Figura 13: Comparação do tempo de execução com e sem prefixo Comparando a execução entre as quatro funções utilizando o prefixo, a que apresenta o melhor desempenho é a Dice, seguida pela Cosseno, pela Jaccard e por último a Distância de Edição. Isto se deve ao fato do número de candidatos filtrados. • 50% inserção • 35% deleção • 15% modificação 26 tipo de banco de dados. O tamanho do q-grams e o do threshold. Esse arquivo foi utilizado para realizar as operações de edição. Os experimentos foram efetuados nos 4 estágios de propagação diferentes e os resultados podem ser observados na Figura 14. Analisando, é possível observar que quanto maior o tamanho do batch, menor é o tempo por operação de edição. Por exemplo, o tempo do batch de 100 para o Estágio 4 foi de 58,571 segundos, ou seja, o tempo médio de cada operação foi de 0,58 segundos, já o batch de 10 para o Estágio 4 apresentou o tempo de 10,647 segundos, um tempo médio de 1,06 segundos. Porém a escolha do tamanho do batch depende da aplicação, pois se for uma base de dados que possua um número pequeno de inserções, exclusões e modificações pode não ser interessante utilizar um batch de 100. Figura 14: Gráfico da propagação de estatística 7 CONCLUSÃO Este artigo apresentou o padrão arquitetural SimDataMapper, que tem por objetivo incorporar uma variedade de funções de similaridade em um único ambiente de aplicação, separando a lógica de domínio e o acesso ao banco de dados, de maneira simples e flexível. Analisando os experimentos é possível observar que a abordagem proposta é flexível e permite a execução eficiente de uma variedade de operações similaridade, incluindo consultas baseadas em seleções e junções e operações de atualização dos dados. Trabalhos futuros visam desenvolver uma aplicação gráfica, onde será possível habilitar a similaridade em um atributo textual e prover todas as funcionalidades apresentadas neste artigo. E utilizar uma análise estatística para definir parâmetros importantes na utilização do padrão arquitetural. Como qual função de similaridade apresenta o melhor resultado para qual 27 REFERÊNCIAS BIBLIOGRÁFICAS Navarro, G. (2001). A guided tour to approximate string matching. ACM computing surveys (CSUR), 33(1):31–88. PostgreSQL (2014). Online manual documentation. Ribeiro, L. A. and Härder, T. (2007). Embedding similarity joins into native xml databases. In Anais do XXII Simpósio Brasileiro de Banco de Dados, pages 285–299. Ribeiro, L. A. and Härder, T. (2011). Generalizing prefix filtering to improve set similarity joins. Information Systems, 36(1):62–78. Ribeiro, L. A., Härder, T., and Pimenta, F. S. (2009). A cluster-based approach to xml similarity joins. In Proc. of the Intl. Database Engineering and Applications Symposium (IDEAS 2009), pages 182–193. Sarawagi, S. and Kirpal, A. (2004). Efficient set joins on similarity predicates. In Proc. of the ACM SIGMOD Intl. Conf. on Management of Data (SIGMOD 2004), pages 743–754. Ukkonen, E. (1992). Approximate string matching with qgrams and maximal matches. Theoretical Computer Science, 92(1):191–211. Wang, J., Li, G., and Feng, J. (2012). Can we beat the prefix filtering?: an adaptive framework for similarity join and search. In Proc. of the ACM SIGMOD Intl. Conf. on Management of Data (SIGMOD 2012), pages 85– 96. Xiao, C., Wang, W., Lin, X., and Yu, J. X. (2008). Efficient similarity joins for near duplicate detection. In Proc. of the 17th Intl. Conf. on World Wide Web (WWW 2008), pages 131–140. Augsten, N., Miraglia, A., Neumann, T., and Kemper, A. (2014). On-the-fly token similarity joins in relational databases. In Proc. of the ACM SIGMOD Intl. Conf. on Management of Data (SIGMOD 2014), pages 1495–1506. Baeza-Yates, R. A. and Ribeiro-Neto, B. A. (2011). Modern Information Retrieval - the concepts and technology behind search, Second edition. Pearson Education Ltd., Harlow, England. Bayardo, R. J., Ma, Y., and Srikant, R. (2007). Scaling up all pairs similarity search. In Proc. of the 16th Intl. Conf. on World Wide Web (WWW 2007), pages 131– 140. Chandel, A., Hassanzadeh, O., Koudas, N., Sadoghi, M., and Srivastava, D. (2007). Benchmarking declarative approximate selection predicates. In Proc. of the ACM SIGMOD Intl. Conf. on Management of Data, pages 353–364. Chaudhuri, S., Ganti, V., and Kaushik, R. (2006). A primitive operator for similarity joins in data cleaning. In Proc. of the 22nd Intl. Conf. on Data Engineering (ICDE 2006), page 5. Chaudhuri, S. and Shim, K. (1999). Optimization of queries with user-defined predicates. ACM Transactions on Database Systems (TODS), 24(2):177–228. Cohen, W. W. (1998). Integration of heterogeneous databases without common domains using queries based on textual similarity. In ACM SIGMOD Record, volume 27, pages 201–212. ACM. Cohen, W. W., Ravikumar, P. D., and Fienberg, S. E. (2003). A comparison of string distance metrics for namematching tasks. In Proc. of IJCAI-03 Workshop on Information Integration on the Web (IIWeb-03), pages 73–78. Fowler, M. (2002). Patterns of enterprise application architecture. Addison-Wesley Longman Publishing Co., Inc. Gravano, L., Ipeirotis, P. G., Jagadish, H. V., Koudas, N., Muthukrishnan, S., and Srivastava, D. (2001). Approximate string joins in a database (almost) for free. In Proc. of 27th Intl. Conf. on Very Large Data Bases, pages 491–500. Gravano, L., Ipeirotis, P. G., Koudas, N., and Srivastava, D. (2003). Text joins in an rdbms for web data integration. In Proc. of the 12th Intl. World Wide Web Conf., pages 90–101. Jr., C. T., Traina, A. J. M., Vieira, M. R., Arantes, A. S., and Faloutsos, C. (2006). Efficient processing of complex similarity queries in rdbms through query rewriting. In CIKM, pages 4–13. Koudas, N., Marathe, A., and Srivastava, D. (2004). Flexible string matching against large databases in practice. In Proc. of the 13th Intl. Conf. on Very Large Data Bases, pages 1078–1086. Koudas, N., Marathe, A., and Srivastava, D. (2007). Propagating updates in spider. In Proc. of the 23rd Intl. Conf. on Data Engineering, pages 1146–1153. 28 A EXPRESSÕES SQL PARA DICE E COSSENO as DICE FROM BaseLength bl, BaseSize bs, BaseRawWeights br, SearchToken st, SearchLength sl WHERE br.tok = st.tok AND st.sid = sl.sid AND bl.tid = br.tid AND bl.len >= (t * sl.len)/(2-t) AND bl.len <= ((2-t)*bl.len) / t GROUP BY st.sid, br.tid, bl.len, sl.len HAVING SUM(log(bs.size/br.df)) >= (t * (bl.len + sl.len))/2 Nesta seção serão apresentadas as consultas SQL para a execução das seleções dos estágios 2, 3 e 4 para as funções Dice e Cosseno. E as junções para as mesmas funções. Consultas de seleção para estágio 2: [Dice] SELECT br.tid,(2*SUM(log(bs.size/br.df)))/ ((log(bs.size)*brl.s1-brl.s2)+sl.len) as DICE FROM BaseSize bs, BaseRawWeights br, BaseRawLength brl, SearchToken st, SearchLength sl WHERE br.tok = st.tok AND st.sid = sl.sid AND brl.tid = br.tid GROUP BY st.sid, br.tid, bs.size, brl.s1, brl.s2, sl.len HAVING SUM(log(bs.size/br.df)) >= (t * ((log(bs.size)*brl.s1 brl.s2) + sl.len))/2 [Cosseno] SELECT br.tid, (SUM(log(bs.size/br.df)))/ sqrt(bl.len * sl.len) as COSSENO FROM BaseLength bl, BaseSize bs, BaseRawWeights br, SearchToken st, SearchLength sl WHERE br.tok = st.tok AND st.sid = sl.sid AND bl.tid = br.tid AND bl.len >= power(t, 2)*sl.len AND bl.len <= sl.len/power(t, 2) GROUP BY st.sid, br.tid, bl.len, sl.len HAVING SUM(log(bs.size/br.df)) >= t * sqrt(bl.len * sl.len) [Cosseno] SELECT br.tid, (SUM(log(bs.size/br.df)))/ sqrt((log(bs.size)*brl.s1-brl.s2) *sl.len) as COSSENO FROM BaseSize bs, BaseRawWeights br, BaseRawLength brl, SearchToken st, SearchLength sl WHERE br.tok = st.tok AND st.sid = sl.sid AND brl.tid = br.tid GROUP BY st.sid, br.tid, bs.size, brl.s1, brl.s2, sl.len HAVING SUM(log(bs.size/br.df)) >= t * sqrt((log(bs.size)*brl.s1 - brl.s2)* sl.len) Consultas de seleção para o estágio 4: [Dice] SELECT bw.tid, (2 * sum(idf))/ (bw.len + sl.len) as DICE FROM BaseWeights bw, SearchToken st, SearchLength sl WHERE bw.tok = st.tok AND st.sid = sl.sid AND bw.len >= (t * sl.len)/(2-t) AND bw.len <= ((2-t)*bw.len) / t GROUP BY st.sid, bw.tid, bw.len, sl.len HAVING SUM(idf)>=(t * (bw.len + sl.len))/2 Consultas de seleção para o estágio 3: [Dice] SELECT br.tid, (2 * SUM(log(bs.size/ br.df)))/(bl.len + sl.len) [Cosseno] SELECT st.sid, bw.tid, (sum(idf))/ 29 sqrt(bw.len * sl.len) as COSSENO FROM BaseWeights bw, SearchToken st, SearchLength sl WHERE bw.tok = st.tok AND st.sid = sl.sid AND bw.len >= power(t, 2) * sl.len AND bw.len <= sl.len/power(t, 2) GROUP BY st.sid, bw.tid, bw.len, sl.len HAVING SUM(idf) >= t * sqrt(bw.len * sl.len) Consultas para executar as junções: [Dice] SELECT bl1.tid, bl2.tid, (2 * SUM(log(bs.size/df.df)))/ (bl1.len + bl2.len) as DICE FROM BaseSearchLength bl1, BaseTokens t1, Base2SearchLength bl2, BaseTokens t2, BaseBase2Size bs, BaseBase2DF df WHERE df.tok = t1.tok AND df.tok = t2.tok AND t1.tid = bl1.tid AND t2.tid = bl2.tid AND bl1.len >= (t * bl2.len)/(2-t) AND bl1.len <= ((2-t)*bl1.len) / t GROUP BY bl1.tid, bl2.tid, bl1.len, bl2.len HAVING SUM(log(bs.size/df.df)) >= (t * (bl1.len + bl2.len))/2 [Cosseno] SELECT bl1.tid, bl2.tid, (SUM(log(bs.size/df.df)))/ sqrt(bl1.len * bl2.len) as COSINE FROM BaseSearchLength bl1, BaseTokens t1, Base2SearchLength bl2, Base2Tokens t2, BaseBase2Size bs, BaseBase2DF df WHERE df.tok = t1.tok AND df.tok = t2.tok AND t1.tid = bl1.tid AND t2.tid = bl2.tid AND bl1.len >= power(t, 2)*bl2.len AND bl1.len <= bl2.len/power(t, 2) GROUP BY bl1.tid, bl2.tid, bl1.len, bl2.len HAVING SUM(log(bs.size/df.df)) >= t * sqrt(bl1.len * bl2.len) 30