Introdução à álgebra relacional: Uma breve introdução sobre o que é álgebra relacional.
A relação entre matemática, álgebra relacional e teoria dos conjuntos é estreita e interdependente. Em seu artigo de 1970, "A Relational Model of Data for Large Shared Data Banks", Edgar F. Codd apresentou o modelo relacional de banco de dados, que se baseia na álgebra relacional e na teoria dos conjuntos.
A álgebra relacional é um sistema formal matemático que permite a manipulação de relações (tabelas) e a realização de operações sobre elas, como união, interseção, diferença, produto cartesiano e junção. A teoria dos conjuntos também é uma parte fundamental da álgebra relacional, já que as operações que são realizadas nas tabelas são semelhantes às operações que podem ser realizadas em conjuntos.
O modelo relacional de banco de dados foi uma revolução na época em que foi proposto, pois apresentou uma abordagem completamente diferente de armazenamento e manipulação de dados em relação aos modelos hierárquicos e em rede que eram utilizados na época. O modelo relacional permite a organização dos dados em tabelas com linhas e colunas, fornecendo uma estrutura clara e consistente para a manipulação dos dados.
A álgebra relacional e a teoria dos conjuntos também têm aplicações em várias áreas da matemática e da ciência da computação, como a lógica, a teoria dos grafos e a teoria da computação. A álgebra relacional, em particular, é usada não apenas na manipulação de bancos de dados, mas também em áreas como redes neurais, aprendizado de máquina e processamento de linguagem natural.
A Álgebra relacional é uma linguagem matemática que descreve operações em conjuntos de dados estruturados em forma de tabelas, conhecidos como relações. Essa linguagem formal é utilizada em bancos de dados relacionais para definir consultas e operações de manipulação de dados. Algumas das operações que podem ser realizadas pela Álgebra relacional incluem seleção (filtragem de dados), projeção (selecionando colunas específicas), junção (combinando informações de várias tabelas), união (combinando informações de duas tabelas), intersecção (retornando informações que aparecem em ambas as tabelas), entre outras.
A Álgebra relacional é amplamente utilizada em sistemas de gerenciamento de bancos de dados relacionais para otimização de consultas e operações. Ela é usada em conjunto com as linguagens SQL (Structured Query Language) para construir consultas e operações de banco de dados, permitindo a realização de consultas precisas e eficientes em bancos de dados relacionais.
O PySpark, que é a interface Python do framework Apache Spark, usa a álgebra relacional em sua API para processamento de dados distribuído. O Spark SQL, que é o módulo de processamento de dados estruturados do Apache Spark, é baseado em álgebra relacional e oferece uma API semelhante à SQL para consulta e manipulação de dados em conjunto com o PySpark. A API do Spark SQL permite aos usuários escrever consultas em SQL e também fornece suporte para funções de agregação, junção, filtro, seleção e outras operações de álgebra relacional. Além disso, o Spark SQL também oferece suporte à API DataFrame, que permite a manipulação de dados estruturados em Python e é baseada em conceitos de álgebra relacional.
A álgebra relacional é essencial para o processamento de dados estruturados em bancos de dados relacionais e em outras aplicações que envolvem manipulação de tabelas e conjuntos de dados. O seu uso permite a criação de consultas precisas e eficientes em bancos de dados, bem como a realização de operações sofisticadas em processamento de dados distribuído, como no caso do PySpark e do Spark SQL.
Por fim, a compreensão dos conceitos de álgebra relacional e teoria dos conjuntos é fundamental para profissionais da área de ciência da computação e tecnologia da informação que desejam trabalhar com bancos de dados e processamento de dados estruturados. É um conhecimento fundamental para o desenvolvimento de sistemas e aplicações que lidam com dados e informações de forma eficiente e organizada.
O BIG Data é caracterizado pelo grande volume, velocidade e variedade de dados que precisam ser armazenados, processados e analisados. Nesse contexto, a Álgebra Relacional é uma das técnicas que pode ser usada para lidar com esses desafios, já que ela permite que consultas precisas e eficientes sejam realizadas em grandes volumes de dados.
Uma das abordagens mais comuns para lidar com BIG Data usando a Álgebra Relacional é a utilização do MapReduce, um modelo de programação que permite o processamento distribuído de grandes volumes de dados em clusters de computadores. O MapReduce é uma técnica que pode ser usada para executar operações de Álgebra Relacional em grandes volumes de dados.
O Apache Hadoop é um framework de processamento distribuído de dados que implementa o modelo MapReduce. O Hadoop é amplamente utilizado em soluções de BIG Data, como o processamento de logs, a análise de dados em tempo real e a análise de dados de mídia social.
O Apache Spark é outro framework de processamento distribuído que é amplamente utilizado em soluções de BIG Data. O Spark oferece suporte para a Álgebra Relacional por meio de sua API Spark SQL. A Spark SQL é uma API que oferece suporte para a execução de consultas SQL em dados distribuídos usando o Spark. Além disso, o Spark SQL oferece suporte para funções de agregação, junção, filtro, seleção e outras operações de Álgebra Relacional.
Consulte o aritgo original aqui: https://dl.acm.org/doi/10.1145/362384.362685
Operações básicas: Descrição das operações básicas da álgebra relacional.
As operações básicas da álgebra relacional incluem:
• Seleção (σ): A seleção é usada para recuperar tuplas de uma tabela que atendem a uma condição específica. Por exemplo, selecionar todos os funcionários com idade superior a 30 anos.
• Projeção (π): A projeção é usada para recuperar colunas específicas de uma tabela. Por exemplo, projetar apenas os nomes dos funcionários em uma tabela.
• União (⋃): A união é usada para combinar duas tabelas com o mesmo esquema e retornar uma tabela que contém todas as tuplas das duas tabelas originais, sem duplicatas.
• Interseção (⋂): A interseção é usada para comparar duas tabelas e retornar uma tabela que contém apenas as tuplas que aparecem em ambas as tabelas originais.
• Produto cartesiano (×): O produto cartesiano é usado para combinar cada tupla em uma tabela com cada tupla em outra tabela, criando uma nova tabela que contém todas as combinações possíveis de tuplas.
• Junção (⨝): A junção é usada para combinar tuplas de duas tabelas relacionadas com base em uma condição de junção. Por exemplo, unir as tabelas de funcionários e departamentos com base no departamento em que cada funcionário trabalha.
Essas operações básicas da álgebra relacional podem ser combinadas para realizar consultas mais complexas em um banco de dados relacional.
Seleção
Na álgebra relacional, a seleção é usada para selecionar informações específicas de uma tabela. É como usar um filtro para selecionar apenas as informações que você precisa. É como usar um filtro em um aplicativo de fotos para selecionar apenas as fotos que contêm determinadas pessoas. A seleção usa símbolos especiais, como o σ, para mostrar que estamos fazendo essa operação. Usando a seleção, podemos filtrar as informações com base em regras que definimos, como idade ou salário. Por exemplo, podemos usar a seleção para encontrar apenas funcionários com mais de 30 anos em uma tabela de funcionários. Dessa forma, podemos trabalhar apenas com as informações que são importantes para nós, economizando tempo e tornando as coisas mais fáceis.
Neste exemplo, "Idade > 30" é a condição de seleção que estamos usando para filtrar as tuplas desejadas. A operação de seleção retornará uma tabela que contém apenas as tuplas (linhas) da tabela "Funcionários" em que a idade é maior que 30 anos.
A operação de seleção é uma das operações básicas da álgebra relacional e é usada em conjunto com outras operações para realizar consultas mais complexas em um banco de dados relacional.
Exemplo:
Selecionar todos os clientes que têm uma idade superior a 25 anos e um salário superior a R$ 5.000,00:
σ(Idade > 25 AND Salário > 5000) (Clientes)
Em SQL:
SELECT *
FROM Clientes
WHERE Idade > 25 AND Salário > 5000;
Pyspark:
from pyspark.sql.functions import col
clientes.select("*").where((col("Idade") > 25) & (col("Salário") > 5000))
Pandas:
clientes[(clientes['Idade'] > 25) & (clientes['Salário'] > 5000)]
Apache beam:
clientes | beam.Filter(lambda row: row['Idade'] > 25 and row['Salário'] > 5000)
Neste exemplo, a operação de seleção é usada para filtrar as tuplas da tabela "Clientes" que atendem à condição especificada, que é "Idade > 25 AND Salário > 5000". A operação de seleção retornará uma tabela com todos os clientes que têm mais de 25 anos e um salário superior a R$ 5.000,00.
Projeção
A projeção na álgebra relacional é como uma lupa que nos permite examinar uma tabela e ver apenas as informações que são importantes para nós. É uma forma de selecionar somente as colunas de uma tabela que queremos ver, criando uma nova tabela com essas informações.
Por exemplo, imagine que temos uma tabela de funcionários com muitas informações, como nome, idade, salário, endereço e assim por diante. Mas, se quisermos ver apenas o nome e o salário dos funcionários, podemos usar a projeção para criar uma nova tabela que contenha apenas essas informações.
A projeção é indicada pelo símbolo grego π, e podemos usá-la para escolher apenas as colunas que queremos ver, ignorando as outras colunas que não são importantes para nós. Por exemplo, se quisermos ver apenas o nome e o salário dos funcionários, podemos usar a projeção da seguinte forma: π(Nome, Salário) (Funcionários).
Dessa forma, a nova tabela que criamos terá apenas o nome e o salário dos funcionários, facilitando muito o trabalho com essas informações. A projeção é uma ferramenta útil para trabalhar com grandes quantidades de informações, pois permite que selecionemos apenas as informações importantes e reduzimos a quantidade de dados que precisamos processar.
Exemplo de projeção
Vamos supor que temos a seguinte tabela "Funcionários" com as seguintes colunas: "Nome", "Idade", "Salário", "Departamento" e "Endereço". Para obtermos o resultado de uma nova tabela com as colunas "Nome" e "Departamento" podemos usar a operação de projeção da seguinte forma:
π(Nome, Departamento) (Funcionários)
Em SQL:
SELECT Nome, Departamento
FROM Funcionários;
Em pyspark:
from pyspark.sql.functions import col
funcionarios_projetados = funcionarios_df.select(col("Nome"), col("Departamento"))
Em Pandas:
funcionarios_projetados = funcionarios_df[["Nome", "Departamento"]]
No Apache Bream:
def projetar_funcionarios(funcionario):
return {"Nome": funcionario["Nome"], "Departamento": funcionario["Departamento"]}
with beam.Pipeline() as pipeline:
funcionarios_pcoll = pipeline | beam.Create(funcionarios)
funcionarios_projetados = funcionarios_pcoll | beam.Map(projetar_funcionarios)
União
A união na álgebra relacional é uma operação que combina duas tabelas em uma só, sem repetir as linhas que aparecem nas duas tabelas. Por exemplo, se você tem duas tabelas com informações sobre funcionários, como nome e cargo, pode usar a união para combiná-las em uma só tabela que contém todas as informações.
A operação de união é representada pelo símbolo ∪ e é usada quando você deseja juntar duas tabelas com as mesmas colunas. Por exemplo, se você tem uma tabela "Funcionários" com nome, departamento e salário, e uma tabela "Contratados" com nome, departamento e data de contratação, pode usar a operação de união para combinar as duas tabelas em uma única tabela que contém todas as informações.
Exemplo de união
Suponha que você tenha duas tabelas: "Funcionários" e "Contratados", ambas com as mesmas colunas "Nome" e "Departamento", mas com informações diferentes.
Para unir as duas tabelas em uma só, sem repetir as linhas que aparecem nas duas tabelas, podemos usar a operação de união. A operação de união é representada pelo símbolo ∪ e é usada da seguinte forma:
Funcionários ∪ Contratados
Em SQL:
SELECT Nome, Departamento FROM Funcionários
UNION
SELECT Nome, Departamento FROM Contratados;
Em pyspark:
from pyspark.sql.functions import col
resultado = funcionarios.select(col("Nome"), col("Departamento")).union(
contratados.select(col("Nome"), col("Departamento"))
Em Pandas:
resultado = funcionarios[['Nome', 'Departamento']].merge(
contratados[['Nome', 'Departamento']], how='outer'
)
resultado = pd.concat([funcionarios[['Nome', 'Departamento']], contratados[['Nome', 'Departamento']]]).drop_duplicates()
No Apache Beam:
with beam.Pipeline() as pipeline:
# Criando um PCollection para cada conjunto de dados
pc_funcionarios = pipeline | 'Criar PC Funcionários' >> beam.Create(funcionarios)
pc_contratados = pipeline | 'Criar PC Contratados' >> beam.Create(contratados)
# Executando a operação de união dos conjuntos
resultado = (pc_funcionarios, pc_contratados) | 'União' >> beam.Flatten()
Interseção
A Interseção é uma operação da álgebra relacional que consiste em comparar dois conjuntos de dados e mostrar somente os elementos que existem em ambos. Em outras palavras, é uma forma de encontrar a "parte em comum" entre os conjuntos.
Por exemplo, se tivermos um conjunto A com os números {1, 2, 3, 4} e um conjunto B com os números {3, 4, 5, 6}, a interseção entre A e B seria o conjunto {3, 4}, já que esses são os únicos números que aparecem em ambos os conjuntos.
Na linguagem da álgebra relacional, a Interseção é representada pelo símbolo de intersecção (∩). Então, se tivermos dois conjuntos de dados chamados "Funcionários" e "Gerentes", poderíamos usar a Interseção para encontrar os funcionários que também são gerentes (ou seja, estão presentes em ambos os conjuntos).
Exemplo de interseção:
O comando para realizar a operação de interseção na álgebra relacional é o "∩". Suponha que temos duas tabelas: uma tabela chamada "A" com as colunas "id" e "nome", e outra tabela chamada "B" com as colunas "id" e "email". Para realizar a interseção entre as tabelas, considerando apenas os que registros que possuem o mesmo "id" nas duas tabelas, utilizamos a seguinte operação que retorna uma nova tabela contendo apenas as linhas que possuem o mesmo valor de "id" em ambas as tabelas.
A ∩ B
No SQL:
SELECT * FROM A
INTERSECT
SELECT * FROM B;
No Pysark:
resultado = dataframeA.intersect(dataframeB)
No Pandas:
resultado = pd.merge(df1, df2, on=['A', 'B'], how='inner')
No apache Beam:
resultado = ({'A': pc_A, 'B': pc_B}
| 'Join com tipo inner join' >> beam.CoGroupByKey()
| 'Selecionar chaves com valores em ambas as coleções'
>> beam.Filter(lambda x: all(key in x[1] for key in ['A', 'B'])))
Produto cartesiano
O produto cartesiano é uma operação na álgebra relacional que combina todas as tuplas de duas relações diferentes para criar uma nova relação. Quando você tem duas relações A e B, o produto cartesiano de A e B resulta em uma nova relação que contém todas as combinações possíveis de tuplas de A e B.
Por exemplo, se você tem duas relações A e B, onde A tem duas tuplas {a1, a2} e B tem três tuplas {b1, b2, b3}, o produto cartesiano entre A e B resultaria em uma nova relação com seis tuplas {(a1, b1), (a1, b2), (a1, b3), (a2, b1), (a2, b2), (a2, b3)}.
Em outras palavras, o produto cartesiano cria todas as possíveis combinações de tuplas entre duas relações. É importante lembrar que o resultado do produto cartesiano pode ser muito grande, especialmente quando você tem muitas tuplas em suas relações.
A fórmula matemática para calcular a combinação do produto cartesiano é simplesmente multiplicar o número de elementos do conjunto A pelo número de elementos do conjunto B. Assim, se A tem n elementos e B tem m elementos, o produto cartesiano de A e B terá n x m elementos. Ou seja, a fórmula é: |A x B| = |A| x |B|
onde |A| é o número de elementos no conjunto A e |B| é o número de elementos no conjunto B. O símbolo "x" representa o produto cartesiano e "|" representa o tamanho do conjunto, ou seja, o número de elementos.
Exemplo de operação cartesiano
A = {1, 2, 3}
B = {4, 5}
O produto cartesiano A x B é a combinação de todos os elementos de A com todos os elementos de B, gerando uma nova relação, onde cada elemento da relação é uma tupla que contém um elemento de A combinado com um elemento de B.
A x B = {(1, 4), (1, 5), (2, 4), (2, 5), (3, 4), (3, 5)}
No SQL:
SELECT *
FROM A
CROSS JOIN B;
No Pyspark:
resultado = dfA.crossJoin(dfB)
No Pandas:
resultado = pd.merge(A.assign(chave=0), B.assign(chave=0), on='chave').drop('chave', axis=1)
No Apache Beam:
produto_cartesiano = (
pc1
| 'Combina com' >> beam.FlatMap(lambda x, pc2: [(x, y) for y in pc2], pc2=pc2)
)
Junção (join)
Junção na álgebra relacional é uma operação que combina duas tabelas (ou relações) a partir de uma condição definida. Essa condição é geralmente uma igualdade entre duas colunas que existem em ambas as tabelas. A junção retorna uma nova tabela que contém todas as colunas das tabelas originais, mas com as linhas combinadas onde a condição de junção é verdadeira. É como se você estivesse unindo duas peças de quebra-cabeça que se encaixam perfeitamente. Por exemplo, se você tiver uma tabela com informações de clientes e outra tabela com informações de pedidos, você pode juntá-las para obter uma tabela que mostre todos os clientes e seus pedidos correspondentes.
Exemplo:
Para obter informações sobre as notas dos alunos em uma determinada turma, você pode usar a operação de junção para combinar as duas tabelas com base na coluna Nome. O resultado será uma nova tabela que contém as informações de ambas as tabelas, mas apenas para os alunos da turma especificada.
Alunos ⋈ Notas
No SQL:
SELECT Alunos.ID, Alunos.Nome, Notas.Disciplina, Notas.Nota
FROM Alunos
INNER JOIN Notas
ON Alunos.ID = Notas.ID;
No Pyspark:
from pyspark.sql.functions import col
join_df = alunos_df.join(notas_df, col("alunos_df.id_aluno") == col("notas_df.id_aluno"), "inner")
No Pandas:
juncao = pd.merge(alunos, notas, on='id_aluno', how='inner')
No Apache beam:
join = (
{'alunos': alunos, 'notas': notas}
| 'CoGroupByKey' >> beam.CoGroupByKey()
| 'Filtrar' >> beam.Filter(lambda x: x[1]['alunos'] and x[1]['notas'])
| 'Map' >> beam.Map(lambda x: (x[0], list(x[1]['alunos'])[0], list(x[1]['notas'])[0]))
)
Mais exemplos de joins
O inner join a seguir é perfeito, tanto df1 quanto df2 estão organizados de forma que o resultado do relacionamento é perfeito, retornando a quantidade de linhas desejada.
Nesta junção, era esperado outro resultado, no entanto, note que o id 2 sumiu afetando a regra de negocio. Analisando as duas tabelas, vemos podemos tirar o grupo da clausula do relacionamento.
No exemplo abaixo criamos uma especie de intra-cartesiano, pois ambas as tabelas tem id duplicados. Absolutamente este não é o resultado esperado pela regra de negocio. Temos de nos certificar que uma das tabelas tenha valores únicos antes de fazer a operação de Join.
É importante garantir que não haja duplicatas nos registros que serão usados para fazer o join, mas não é necessário que uma das tabelas tenha valores únicos.
O join em si não repete registros, ele apenas combina as informações das tabelas baseado nas colunas especificadas. Se uma tabela tiver valores duplicados em uma ou mais colunas que estão sendo usadas para o join, então esses valores duplicados serão repetidos no resultado final, mas isso não significa que os outros valores serão excluídos.
Não é necessário que uma das tabelas tenha valores únicos antes de fazer a operação de join. O que pode ser necessário, dependendo do caso, é garantir que não haja duplicatas nos registros que serão usados para fazer o join.
No exemplo abaixo, se a tabela da direita tiver o id 1 repetido 2 vezes e a tabela da esquerda tiver os ids 1 e 2, o resultado final do join terá 2 linhas, uma para cada ocorrência do id 1 na tabela da direita e uma para o id 2 na tabela da esquerda. Ou seja, o id 2 ainda aparecerá no resultado final.
Por hoje é isso pessoal, o assunto sobre álgebra relacional é extenso quando começamos explorar os desdobramentos.