Quais são alguns bancos de dados domésticos simples e fáceis de usar?

As linguagens de processamento de dados de código aberto baseadas em JVM incluem principalmente Kotlin, Scala e SPL. A seguir, uma comparação horizontal dos três para descobrir a linguagem de processamento de dados mais eficiente. Os cenários aplicáveis ​​deste artigo são definidos para processamento de dados comum e lógica de negócios no desenvolvimento de projetos, principalmente dados estruturados, big data e alto desempenho não são o foco, e não envolvem cenários especiais como fluxo de mensagens e computação científica.

Recursos básicos

superfície de adaptação

A intenção original do projeto do Kotlin é desenvolver Java com maior eficiência, podendo ser aplicado a qualquer cenário de aplicação envolvendo Java. versatilidade. Scala foi originalmente projetada para ser uma linguagem de desenvolvimento de uso geral que integra paradigmas de programação modernos. Na prática, é usado principalmente para processamento de big data de back-end. Raramente aparece em outros tipos de projetos e não é tão versátil quanto Kotlin . O design original do SPL é uma linguagem de processamento de dados profissional. A prática é consistente com a intenção original. É adequado para processamento de dados front-end e back-end e processamento de dados grandes e pequenos. Os cenários de aplicação são relativamente focados e o versatilidade não é tão boa quanto Kotlin.

paradigma de programação

Kotlin se concentra na programação orientada a objetos, mas também suporta programação funcional. Scala suporta ambos os paradigmas, a programação orientada a objetos é mais completa que Koltin, e a programação funcional é mais conveniente que Koltin. Pode-se dizer que o SPL não suporta programação orientada a objetos, possui o conceito de objetos, mas não herda e sobrecarrega esses conteúdos.A programação funcional é mais conveniente que Kotlin.

modo operacional

Kotlin e Scala são linguagens compiladas e SPL é uma linguagem interpretada. As linguagens interpretadas são mais flexíveis, mas o desempenho do mesmo código será um pouco pior. No entanto, o SPL possui funções de biblioteca ricas e eficientes, o desempenho geral não é fraco e geralmente é mais vantajoso em face de big data.

biblioteca de classes externa

Kotlin pode usar todas as bibliotecas Java, mas não possui bibliotecas profissionais de processamento de dados. Scala também pode usar todas as bibliotecas de classes Java e possui uma biblioteca de classes de processamento de big data (Spark) profissional integrada. A SPL possui funções de processamento de dados profissionais integradas, que fornecem um grande número de operações básicas com menor complexidade de tempo. Normalmente, não são necessárias bibliotecas de classes externas Java. Em casos especiais, elas podem ser chamadas em funções personalizadas.

IDE e depuração

Todos os três têm IDEs gráficos e recursos completos de depuração. O IDE do SPL é especialmente projetado para processamento de dados. Os objetos de dados estruturados são apresentados em forma de tabela, o que é mais conveniente de observar. Os IDEs de Kotlin e Scala são de uso geral e não são otimizados para processamento de dados, portanto, objetos de dados estruturados não podem ser facilmente observado.

dificuldade de aprendizagem

Kotlin é um pouco mais difícil de aprender do que Java, e aqueles que são proficientes em Java podem aprendê-lo facilmente. O objetivo do Scala é superar o Java, que é muito mais difícil de aprender do que o Java. O objetivo do SPL é simplificar a codificação do Java e até mesmo do SQL. Muitos conceitos são deliberadamente simplificados e a dificuldade de aprendizado é muito baixa.

quantidade de código

A intenção original do Kotlin é melhorar a eficiência de desenvolvimento do Java. Os oficiais afirmam que o tamanho geral do código é apenas 20% do Java, o que pode ser devido ao pouco profissionalismo da biblioteca de classes de processamento de dados e ao tamanho real do código em esta consideração não é muito reduzida. Scala tem muito açúcar sintático, e a biblioteca de classes de processamento de big data é mais profissional, mas a quantidade de código é muito menor que a do Kotlin. SPL é usado apenas para processamento de dados, e tem o maior profissionalismo. Juntamente com as características de forte capacidade de expressão da linguagem interpretada, a quantidade de código para concluir a mesma tarefa é muito menor do que as duas anteriores (haverá exemplos de comparação posteriormente) .Pode-se explicar que a dificuldade de aprendizagem é menor.

gramática

tipo de dados

Tipos de dados atômicos: todos os três são suportados, como Short, Int, Long, Float, Double, Boolean

Tipos de data e hora: Kotlin não possui tipos de data e hora fáceis de usar, geralmente Java. Tanto o Scala quanto o SPL têm tipos de data e hora especializados e convenientes.

Tipos de dados distintos: Kotlin suporta caracteres não numéricos Char e o tipo anulável Any?. Scala suporta tuplas (coleções genéricas de comprimento fixo), BigDecimal integrado. O SPL suporta chaves ordinais multicamadas de alto desempenho com BigDecimal integrado.

Tipos de coleção: Kotlin e Scala suportam Set, List, Map. SPL suporta sequências (coleções genéricas ordenadas, semelhantes a List).

Tipo de dados estruturados: Kotlin tem uma coleção de registros List<EntityBean>, mas não tem metadados e não é profissional o suficiente. Scala tem tipos de dados estruturados profissionais, incluindo Row, RDD, DataSet, DataFrame (este artigo usa isso como exemplo), etc. A SPL possui tipos de dados estruturados profissionais, incluindo registro, tabela de sequência (este artigo usa isso como exemplo), tabela de compactação de tabela interna, cursor preguiçoso de memória externa etc.

O Scala possui recursos exclusivos de conversão implícita, que teoricamente podem converter entre quaisquer tipos de dados (incluindo parâmetros, variáveis, funções e classes) e podem alterar ou aprimorar facilmente as funções originais.

Processamento do processo

Todos os três suportam execução sequencial básica, julgamento de ramificações e loops. Em teoria, o processamento de processos arbitrariamente complexos pode ser realizado. Esse aspecto não é muito discutido. A seguir, concentra-se na comparação da conveniência da estrutura de loop para dados agregados. Tomando a relação de cálculo como exemplo, o código Kotlin:

mData.forEachIndexed{index,it->
if(index>0) it.Mom= it.Amount/mData[index-1].Amount-1
}

A função forEachIndexed do Kotlin tem sua própria variável de número de série e variável de membro, que é mais conveniente para loop de coleção, suporta registros de subscritos e pode executar facilmente cálculos de linha cruzada. A desvantagem do Kotlin é o manuseio extra de arrays fora dos limites.

Código escala:

val w = Window.orderBy(mData("SellerId"))
mData.withColumn("Mom", mData ("Amount")/lag(mData ("Amount"),1).over(w)-1)

Cálculos de linhas cruzadas Scala não precisam lidar com arrays fora dos limites, o que é mais conveniente do que Kotlin. No entanto, os objetos de dados estruturados do Scala não suportam registros subscritos e só podem usar a função lag para mover como um todo, o que não é conveniente para dados estruturados. A função lag não pode ser usada para o versátil forEach, mas com uma função de loop de função única, como withColumn. Para manter a unidade subjacente do estilo de programação funcional e do estilo SQL, a função lag também deve cooperar com a função window (a função de transição do Python não possui esse requisito) e o código geral parece mais complicado que o Kotlin.

Código SPL:

mData.(Mom=Amount/Amount[-1]-1)

O SPL realizou várias otimizações no controle de fluxo de objetos de dados estruturados. Semelhante ao forEach, a função de loop mais comum e comumente usada, o SPL pode ser expresso diretamente entre parênteses, o que é simplificado ao extremo. SPL também tem uma função de movimento, mas a sintaxe "[posição relativa]" mais intuitiva é usada aqui, que é mais poderosa que o posicionamento absoluto de Kotlin ao realizar cálculos de linha cruzada e mais conveniente que a função de movimento de Scala. Além do código acima, o SPL possui mais funções de processamento de processos para dados estruturados, como: pegar um lote de registros em vez de um registro em cada rodada de loops; fazer loops quando um valor de campo é alterado.

Expressões lambda

As expressões lambda são implementações simples de funções anônimas e seu objetivo é simplificar a definição de funções, especialmente as diversas funções de computação de conjunto. Kotlin suporta expressões Lambda, mas devido ao relacionamento de linguagens compiladas, é difícil especificar facilmente expressões de parâmetro como parâmetros de valor ou parâmetros de função. Somente regras de interface complexas podem ser projetadas para distingui-las, e existem até as chamadas interfaces dedicadas para funções de ordem superior, o que torna a expressão Lambda do Kotin difícil de escrever e carece de profissionalismo no processamento de dados. Alguns exemplos:

"abcd".substring( 1,2)						//值参数
"abcd".sumBy{ it.toInt()}					//函数参数
mData.forEachIndexed{ index,it-> if(index>0) it.Mom=…}		//函数参数的函数带多个参数

A expressão Lambda do Koltin não é profissional o suficiente e também mostra que o nome da variável (it) do objeto de dados estruturados deve ser usado ao usar o campo, e o nome da tabela pode ser omitido ao calcular uma única tabela como SQL.

Como uma linguagem compilada, a expressão Lambda do Scala não é muito diferente do Kotlin, ela também precisa projetar regras de interface complexas, o que também é difícil de escrever, então não vou dar um exemplo aqui. Ao calcular mais do que o período anterior, o nome da variável do objeto de dados estruturados também deve ser colocado antes do campo ou a função col deve ser usada, como mData ("Valor") ou col ("Valor"), embora possa ser complementado com açúcar sintático, escrito como $"Amount" ou 'Amount, mas muitas funções não suportam essa forma de escrita, e insistir em fazer as pazes tornará o estilo inconsistente.

A expressão Lambda da SPL é simples e fácil de usar, e mais profissional que as duas anteriores, o que está relacionado às características de sua linguagem interpretada. As linguagens interpretadas podem facilmente inferir parâmetros de valor e parâmetros de função, não existe a chamada interface especial complexa para funções de ordem superior e todas as interfaces de função são igualmente simples. Alguns exemplos:

mid("abcd",2,1)							//值参数
Orders.sum(Amount*Amount)					//函数参数
mData.(Mom=Amount/Amount[-1]-1)					//函数参数的函数带多个参数

A SPL pode usar nomes de campo diretamente sem nomes de variáveis ​​de objetos de dados estruturados, como:

Orders.select(Amount>1000 && Amount<=3000 && like(Client,"*S*"))

A maioria das funções de loop do SPL tem variáveis ​​de membro padrão ~ e variáveis ​​ordinais #, que podem melhorar significativamente a conveniência da escrita de código, especialmente para cálculos de dados estruturados. Por exemplo, para recuperar registros em posições pares:

Students.select(# % 2==0)

Encontre os 3 primeiros de cada grupo:

Orders.group(SellerId;~.top(3;Amount))

Opções de função SPL e parâmetros de nível

Vale ressaltar que, para melhorar ainda mais a eficiência do desenvolvimento, o SPL também fornece uma sintaxe de função exclusiva.

Quando há um grande número de funções com funções semelhantes, a maioria das linguagens de programação só pode ser distinguida por nomes ou parâmetros diferentes, o que é inconveniente de usar. A SPL fornece opções de função muito exclusivas, de modo que funções com funções semelhantes podem compartilhar um nome de função e usar apenas opções de função para distinguir a diferença. Por exemplo, a função básica da função select é filtrar. Se apenas o primeiro registro que atende às condições for filtrado, a opção @1 pode ser usada:

T.select@1(Amount>1000)

Para filtragem rápida de dados ordenados com dicotomia, use @b:

T.select@b(Amount>1000)

As opções de função também podem ser combinadas, por exemplo:

Orders.select@1b(Amount>1000)

Os parâmetros de algumas funções são complexos e podem ser divididos em várias camadas. As linguagens de programação convencionais não possuem um esquema de sintaxe especial para isso e só podem gerar objetos de dados estruturados em várias camadas e depois passá-los, o que é muito problemático. O SQL usa palavras-chave para separar os parâmetros em vários grupos, o que é mais intuitivo e simples, mas usará muitas palavras-chave e tornará a estrutura da instrução inconsistente. O SPL inventou parâmetros hierárquicos de forma criativa para simplificar a expressão de parâmetros complexos e dividiu os parâmetros em três camadas, de alto a baixo, por meio de ponto e vírgula, vírgula e dois pontos:

join(Orders:o,SellerId ; Employees:e,EId)

fonte de dados

Tipo de fonte de dados

Em princípio, o Kotlin pode suportar todas as fontes de dados Java, mas o código é muito complicado, a conversão de tipo é problemática e a estabilidade é ruim. Isso ocorre porque o Kotlin não possui uma interface de acesso à fonte de dados integrada nem é otimizado para processamento de dados estruturados (exceto para a interface JDBC). Nesse sentido, também pode-se dizer que ele não suporta diretamente nenhuma fonte de dados, podendo usar apenas bibliotecas de classes de terceiros Java. Felizmente, o número de bibliotecas de classes de terceiros é grande o suficiente.

Scala suporta muitos tipos de fontes de dados, e seis interfaces de fonte de dados são integradas e otimizadas para processamento de dados estruturados, incluindo: JDBC, CSV, TXT, JSON, formato de armazenamento de coluna Parquet, formato de armazenamento de coluna ORC, embora outras interfaces de fonte de dados sejam não integrados, eles podem usar bibliotecas de terceiros desenvolvidas pelo grupo da comunidade. Scala fornece uma especificação de interface de fonte de dados que requer bibliotecas de classe de terceiros para gerar objetos de dados estruturados.Interfaces comuns de terceiros incluem XML, Cassandra, HBase e MongoDB.

A SPL tem as interfaces de fonte de dados mais integradas e é otimizada para processamento de dados estruturados, incluindo:

JDBC (ou seja, todos os RDBs)

CSV, TXT, JSON, XML, Excel

HBase, HDFS, Hive, Spark

Salesforce, nuvem Alibaba

Restful, WebService, Webcrawl

Elasticsearch, MongoDB, Kafka, R2dbc, FTP

Cassandra, DynamoDB, influxDB, Redis, SAP

Essas fontes de dados podem ser usadas diretamente, o que é muito conveniente. Para outras fontes de dados que não estão listadas, o SPL também fornece especificações de interface.Contanto que a especificação seja emitida como um objeto de dados estruturados do SPL, cálculos subsequentes podem ser executados.

comparação de código

Pegue um arquivo CSV canônico como exemplo para comparar o código de análise em três idiomas. Kotlin:

val file = File("D:\\data\\Orders.txt")
data class Order(var OrderID: Int,var Client: String,var SellerId: Int, var Amount: Double, var OrderDate: Date)
var sdf = SimpleDateFormat("yyyy-MM-dd")
var Orders=file.readLines().drop(1).map{
var l=it.split("\t")
var r=Order(l[0].toInt(),l[1],l[2].toInt(),l[3].toDouble(),sdf.parse(l[4]))
r
}
var resutl=Orders.filter{
it.Amount>= 1000 && it.Amount < 3000}

Koltin não tem profissionalismo, e geralmente tem que escrever código para ler CSV, incluindo definir a estrutura de dados com antecedência e analisar manualmente o tipo de dados na função de loop.O código geral é bastante complicado. Também pode ser lido com bibliotecas de classes como OpenCSV, embora o tipo de dado não precise ser analisado no código, ele deve ser definido no arquivo de configuração, e o processo de implementação não é necessariamente simples.

Scala é profissional e tem uma interface integrada para analisar CSV. O código é muito mais curto que Koltin:

val spark = SparkSession.builder().master("local").getOrCreate()
val Orders = spark.read.option("header", "true").option("sep","\t").option("inferSchema", "true").csv("D:/data/orders.csv").withColumn("OrderDate", col("OrderDate").cast(DateType))
Orders.filter("Amount>1000 and Amount<=3000")

Scala tem problemas para analisar os tipos de dados, mas não tem falhas óbvias.

O SPL é mais profissional, com apenas uma linha para análise e cálculo:

T("D:/data/orders.csv").select(Amount>1000 && Amount<=3000)

Computação de origem cruzada

A linguagem de processamento de dados JVM é altamente aberta e possui recursos suficientes para associar, mesclar e agregar diferentes origens de dados.

Kotlin não é profissional o suficiente, não só carece de interfaces de fonte de dados embutidas, mas também carece de funções de computação de fonte cruzada. Ele só pode ser implementado por código escrito. Supondo que a tabela de funcionários e a tabela de pedidos tenham sido obtidas de fontes de dados diferentes, agora associe as duas:

data class OrderNew(var OrderID:Int ,var Client:String, var SellerId:Employee ,var Amount:Double ,var OrderDate:Date )
val result = Orders.map { o->var emp=Employees.firstOrNull{ it.EId==o.SellerId
}
emp?.let{ OrderNew(o.OrderID,o.Client,emp,o.Amount,o.OrderDate)
}
}
.filter {o->o!=null}

É fácil ver as deficiências do Kotlin. Enquanto o código for longo, a expressão Lambda se torna difícil de ler e não é tão fácil de entender quanto o código comum; a estrutura de dados associada precisa ser definida antecipadamente, o que tem pouca flexibilidade e afeta a fluência da resolução de problemas.

O Scala é mais profissional que o Kotlin. Ele não apenas possui várias interfaces de fonte de dados integradas, mas também fornece funções para computação entre fontes. O mesmo cálculo, o código Scala é muito mais simples:

val join=Orders.join(Employees,Orders("SellerId")===Employees("EId"),"Inner")

Pode-se observar que Scala não só possui objetos e funções dedicados ao cálculo de dados estruturados, como também funciona bem com a linguagem Lambda, o código é mais fácil de entender e não há necessidade de definir antecipadamente a estrutura dos dados.

SPL é mais profissional, objetos de dados estruturados são mais profissionais, funções de computação entre fontes são mais convenientes e o código é mais curto:

join(Orders:o,SellerId;Employees:e,EId)

Formato de armazenamento próprio

Os dados intermediários usados ​​repetidamente são geralmente salvos como um arquivo local em um determinado formato para melhorar o desempenho da busca. O Kotlin suporta arquivos em vários formatos e teoricamente pode armazenar e recalcular dados intermediários, mas como não é profissional em processamento de dados, as operações básicas de leitura e gravação exigem a gravação de grandes pedaços de código, o que equivale a não ter um formato de armazenamento próprio. .

Scala suporta uma variedade de formatos de armazenamento, entre os quais os arquivos em parquet são comumente usados ​​e fáceis de usar. Parquet é um formato de armazenamento de código aberto que suporta armazenamento de colunas e pode armazenar uma grande quantidade de dados.Os resultados de cálculos intermediários (DataFrame) podem ser facilmente convertidos de e para arquivos parquet. Infelizmente, os índices para parquet ainda não estão maduros.

val df = spark.read.parquet("input.parquet")
val result=df.groupBy(data("Dept"),data("Gender")).agg(sum("Amount"),count("*"))
result.write.parquet("output.parquet")

SPL suporta btx e ctx dois formatos de armazenamento binário privado, btx é um armazenamento de linha simples, ctx suporta armazenamento de linha, armazenamento de coluna, índice, pode armazenar uma grande quantidade de dados e realizar computação de alto desempenho, resultados de cálculo intermediários (tabela de sequência / cursor ) pode ser comparado com isso Os dois arquivos podem ser facilmente convertidos um para o outro.

UMA
1 =file("input.ctx").open()
2 =A1.cursor(Dept,Gender,Amount).groups(Dept,Gender;sum(Amount):amt,count(1):cnt)
3 =file("output.ctx").create(#Dept,#Gender,amt,cnt).append(A2.cursor())

Computação de Dados Estruturados

objeto de dados estruturados

O núcleo do processamento de dados é a computação, especialmente a computação de dados estruturados. O grau profissional de objetos de dados estruturados determina profundamente a conveniência do processamento de dados.

Kotlin não tem um objeto de dados estruturados profissional e List<EntityBean> é frequentemente usado para cálculo de dados estruturados, no qual EntityBean pode usar a classe de dados para simplificar o processo de definição.

List é uma coleção ordenada (repetível), e o Kotlin suporta todas as funções que envolvem números de membros e coleções. Por exemplo, para acessar membros por número de série:

Orders[3]						//按下标取记录,从0开始
Orders.take(3)						//前3条记录
Orders.slice(listOf(1,3,5)+IntRange(7,10))		//下标是1、3、5、7-10的记录

Você também pode levar os membros por seus números recíprocos:

Orders.reversed().slice(1,3,5)				//倒数第1、3、5条
Orders.take(1)+Orders.takeLast(1)			//第1条和最后1条

Cálculos envolvendo ordem são relativamente difíceis. Kotlin suporta conjuntos de contagem ordenados e é mais conveniente realizar cálculos relacionados. Como um tipo de coleção, List é bom em funções como adição, exclusão, modificação, interseção e divisão de membros da coleção. Mas List não é um objeto de dados estruturado profissional.Uma vez que as funções relacionadas à estrutura de campo estão envolvidas, Kotlin é difícil de implementar. Por exemplo, pegue dois campos em Pedidos para formar um novo objeto de dados estruturados.

data class CliAmt(var Client: String, var Amount: Double)
var CliAmts=Orders.map{it.let{CliAmt(it.Client,it.Amount) }}

As funções acima são muito usadas e são equivalentes à simples instrução SQL selecione Client, Amount from Orders, mas o Kotlin é muito complicado de escrever, não apenas para definir uma nova estrutura com antecedência, mas também para codificar a atribuição de Campos. A simples função de pegar campos é tão complicada, e as funções avançadas são mais problemáticas, como: pegar pelo número de série do campo, pegar por parâmetro, obter uma lista de nomes de campo, modificar a estrutura do campo, definir chaves e índices nos campos, consultar e calculando por campo.

Scala também tem List, que não é muito diferente de Kotlin, mas Scala projetou um objeto de dados mais profissional DataFrame (e RDD, DataSet) para processamento de dados estruturados.
DataFrame é um fluxo de dados estruturado, que é um pouco semelhante ao conjunto de resultados do banco de dados. É uma coleção não ordenada, portanto, não suporta pressionar o número para buscar e só pode ser implementado disfarçadamente. Por exemplo, o 10º registro:

Orders.limit(10).tail(1)(0)						

É concebível que todos os cálculos relacionados à ordem, DataFrame sejam mais difíceis de implementar, como intervalo, média móvel, ordenação reversa e assim por diante.
Além dos dados não ordenados, o DataFrame não suporta modificação (recurso imutável), caso queira alterar os dados ou a estrutura, deve-se gerar um novo DataFrame. Por exemplo, para modificar o nome do campo, isso é feito copiando o registro:

Orders.selectExpr("Client as Cli")					

O DataFrame suporta cálculos de conjuntos comuns, como divisão, mesclagem e mesclagem cruzada, em que a união pode ser obtida combinando conjuntos para remover duplicatas, mas como é implementado copiando registros, o desempenho dos cálculos de conjuntos geralmente não é alto.
Embora existam muitas deficiências, o DataFrame é um objeto de dados estruturado profissional e a capacidade de acessar campos está além do alcance do Kotlin. Por exemplo, para obter uma lista de metadados/nomes de campos:

Orders.schema.fields.map(it=>it.name).toList

Também é conveniente usar campos para buscar números, por exemplo, para buscar dois campos para formar um novo dataframe:

Orders.select("Client","Amount")				//可以只用字段名

Ou forme um novo DataFrame com colunas computadas:

Orders.select(Orders("Client"),Orders("Amount")+1000)		//不能只用字段名	

Infelizmente, o DataFrame só suporta a referência a campos por nome em forma de string e não suporta números de série de campo ou nomes padrão, o que é inconveniente em muitos cenários. Além disso, o DataFrame não oferece suporte à definição de índices, portanto, a consulta aleatória de alto desempenho não pode ser executada e o profissionalismo ainda é falho.

O objeto de dados estruturados do SPL é uma tabela de sequência, que tem as vantagens de ser bastante profissional, fácil de usar e expressiva.
Acesse membros por número de sequência:

Orders(3)							//按下标取记录,从1开始
Orders.to(3)							//前3条记录
Orders.m(1,3,5,7:10)						//序号是1、3、5、7-10的记录

O registro é feito pelo número recíproco. A característica única é que ele suporta o sinal negativo para indicar o recíproco, o que é mais profissional e mais conveniente que o Kotlin:

Orders.m(-1,-3,-5)						//倒数第1,3,5条
Orders.m(1,-1)							//第1条和最后1条

Como um tipo de conjunto, a tabela de sequência também suporta as funções de adição, exclusão, modificação, interseção, mesclagem, divisão e divisão de membros do conjunto. Como a tabela de sequência é uma coleção mutável como a List, o cálculo da coleção usa os registros livres o máximo possível em vez de copiar os registros, o desempenho é muito melhor que o de Scala e o uso de memória também é menor.
A tabela de sequência é um objeto de dados estruturado profissional, além de funções relacionadas à coleção, mais importante, pode acessar facilmente os campos. Por exemplo, para obter uma lista de nomes de campo:

Orders.fname()							

Pegue dois campos para formar uma nova tabela de sequência:

Orders.new(Client,Amount)

Forme uma nova tabela de sequência com colunas computadas:

Orders.new(Client,Amount*0.2)

Modifique o nome do campo:

Orders.alter(;OrderDate)					//不复制记录

Em alguns cenários, você precisa acessar campos com números de campo ou nomes padrão. A SPL fornece métodos de acesso correspondentes:

Orders(Client)							//按字段名(表达式取)
Orders([#2,#3])							//按默认字段名取
Orders.field(“Client”)						//按字符串(外部参数)
Orders.field(2)							//按字段序号取

Como um objeto de dados estruturado profissional, a tabela de sequência também suporta a definição de chaves e índices em campos:

Orders.keys@i(OrderID)						//定义键,同时建立哈希索引
Orders.find(47)							//用索引高速查找

função de cálculo

O Kotlin suporta algumas funções básicas de cálculo, incluindo: filtragem, classificação, desduplicação, mesclagem cruzada de conjuntos, várias agregações e agrupamento e resumo. No entanto, essas funções são todas para coleções comuns.Se o destino de cálculo for alterado para objetos de dados estruturados, a biblioteca de funções de cálculo é muito insuficiente e geralmente é complementada por codificação física para realizar o cálculo. Existem muitas operações básicas de conjunto que não são suportadas pelo Kotlin e só podem ser implementadas por codificação, incluindo: associação, função de janela, classificação, linha a coluna, mesclagem, pesquisa binária etc. Entre elas, mesclagem e busca binária são operações relacionadas à ordem.Como a Lista Kotlin é um conjunto ordenado, não é muito difícil implementar tais operações por codificação. Em geral, a biblioteca de funções do Kotlin pode ser considerada fraca diante da computação de dados estruturados.

As funções de computação do Scala são relativamente ricas e todas são projetadas para objetos de dados estruturados, incluindo funções não suportadas pelo Kotlin: classificação, associação, função de janela, linha a coluna, mas basicamente não além da estrutura do SQL. Existem também algumas operações básicas de conjunto que não são suportadas pelo Scala, especialmente aquelas relacionadas à ordem, como mesclagem e busca binária. Como o Scala DataFrame usa o conceito de desordem de dados em SQL, é muito difícil implementar tais operações mesmo codifique você mesmo. Em geral, a biblioteca de funções do Scala é mais rica que Kotlin, mas as operações básicas ainda estão faltando.

A SPL tem as funções de computação mais abundantes e todas são projetadas para objetos de dados estruturados. A SPL enriquece muito o conteúdo das operações de dados estruturados e projeta muito conteúdo além do SQL. Claro, também é uma função que Scala/Kotlin faz não suporta, como Cálculo ordenado: Mesclar, pesquisa binária, registro por intervalo, número de sequência de registros elegíveis; além de agrupamento equivalente regular, agrupamento de enumeração, agrupamento de alinhamento e agrupamento ordenado também são suportados; tipos de associação são divididos em chaves estrangeiras e filhos primários; chaves primárias são suportadas para restringir dados, índice de suporte para consulta rápida; consulta recursiva para dados de vários níveis (associação de várias tabelas ou Json\XML), etc.

Tomando o agrupamento como exemplo, além do agrupamento equivalente regular, o SPL também fornece mais esquemas de agrupamento:

Agrupamento de enumeração: o agrupamento é baseado em várias expressões condicionais e os registros que atendem às mesmas condições são agrupados em um grupo.

Agrupamento de alinhamento: O agrupamento é baseado em um conjunto externo. Registros cujos valores de campo são iguais aos membros do conjunto são agrupados em um grupo. A ordem dos grupos é consistente com a ordem dos membros do conjunto. Vazio grupos são permitidos. registros pertencentes a esta coleção".

Agrupamento ordenado: O agrupamento é baseado em campos já ordenados. Por exemplo, um novo grupo é criado quando um campo muda ou uma determinada condição é estabelecida. A SPL fornece diretamente esse agrupamento ordenado, que pode ser feito adicionando uma opção ao função de agrupamento.É muito simples e o desempenho de computação é melhor. Outras linguagens (incluindo SQL) não possuem esse agrupamento e só podem converter laboriosamente para o agrupamento tradicional equivalente ou codificá-lo você mesmo.

Vamos dar alguns exemplos gerais para ter uma ideia das diferenças na forma como essas três linguagens computam funções.

ordenar

Ordenar por ordem do cliente, quantidade na ordem inversa. Kotlin:

Orders.sortedBy{it.Amount}.sortedByDescending{it.Client}

O código Kotlin não é longo, mas ainda há inconvenientes, incluindo: a ordem inversa e a ordem positiva são duas funções diferentes, o nome do campo deve conter o nome da tabela e a ordem dos campos escrita no código é oposta à classificação real ordem.

Escala:

Orders.orderBy(Orders("Client"),-Orders("Amount"))

Scala é muito mais simples, o sinal negativo representa a ordem inversa e a ordem dos campos escritos pelo código é a mesma da ordem de classificação. Infelizmente, os campos ainda precisam ter nomes de tabelas; linguagens compiladas só podem usar strings para implementar a análise dinâmica de expressões, resultando em estilos de código inconsistentes.

SPL:

Orders.sort(Client,-Amount)

O código SPL é mais simples, os campos não precisam ter nomes de tabela e o estilo de código da linguagem interpretada é fácil de unificar.

Resumo do grupo

Kotlin:

data class Grp(var Dept:String,var Gender:String) 
data class Agg(var sumAmount: Double,var rowCount:Int)
var result1=data.groupingBy{Grp(it!!.Dept,it.Gender)}
.fold(Agg(0.0,0),{acc, elem -> Agg(acc.sumAmount + elem!!.Amount,acc.rowCount+1)})
.toSortedMap(compareBy<Grp> { it.Dept }.thenBy { it.Gender })

O código Kotlin é complicado, não apenas usando as funções groupingBy e fold, mas também codificando para obter agrupamento e sumarização. Quando uma nova estrutura de dados aparece, ela deve ser definida com antecedência antes de poder ser usada, como a estrutura de dois campos agrupada e a estrutura de dois campos agregada, que não apenas tem pouca flexibilidade, mas também afeta a fluência da resolução de problemas . A classificação final deve ser consistente com a ordem do resultado em outros idiomas e não é obrigatória.

Escala:

val result=data.groupBy(data("Dept"),data("Gender")).agg(sum("Amount"),count("*"))

O código Scala é muito mais simples, não apenas fácil de entender, mas também não precisa definir estruturas de dados antecipadamente.

SPL:

data.groups(Dept,Gender;sum(Amount),count(1))

O código SPL é o mais simples e sua capacidade expressiva não é inferior à do SQL.

Computação associativa

Duas tabelas possuem campos com o mesmo nome, que são relacionados e agrupados. Código Kotlin:

data class OrderNew(var OrderID:Int ,var Client:String, var SellerId:Employee ,var Amount:Double ,var OrderDate:Date )
val result = Orders.map { o->var emp=Employees.firstOrNull{it.EId==o.EId}
emp?.let{ OrderNew(o.OrderID,o.Client,emp,o.Amount,o.OrderDate)}
}
.filter {o->o!=null}
data class Grp(var Dept:String,var Gender:String) 
data class Agg(var sumAmount: Double,var rowCount:Int)
var result1=data.groupingBy{Grp(it!!.EId.Dept,it.EId.Gender)}
.fold(Agg(0.0,0),{acc, elem -> Agg(acc.sumAmount + elem!!.Amount,acc.rowCount+1)})
.toSortedMap(compareBy<Grp> { it.Dept }.thenBy { it.Gender })

O código Kotlin é complicado e novas estruturas de dados devem ser definidas em muitos lugares, incluindo resultados de associação, estruturas de dois campos agrupadas e estruturas de dois campos agregadas.

Escala

val join=Orders.as("o").join(Employees.as("e"),Orders("EId")===Employees("EId"),"Inner")
val result= join.groupBy(join("e.Dept"), join("e.Gender")).agg(sum("o.Amount"),count("*"))

Scala é muito mais simples que Kolin, sem definir estruturas de dados de forma complicada e sem hardcoding.

SPL é mais simples:

join(Orders:o,SellerId;Employees:e,EId).groups(e.Dept,e.Gender;sum(o.Amount),count(1))

Comparação abrangente de processamento de dados

O conteúdo do CSV não é padronizado. Cada três linhas corresponde a um registro, e a segunda linha contém três campos (ou seja, uma coleção de coleções). O arquivo é organizado em um objeto de dados estruturado padronizado e classificado pela 3ª e 4º campos.

Kotlin:

data class Order(var OrderID: Int,var Client: String,var SellerId: Int, var Amount: Double, var OrderDate: Date)
var Orders=ArrayList<Order>()
var sdf = SimpleDateFormat("yyyy-MM-dd")
var raw=File("d:\\threelines.txt").readLines()
raw.forEachIndexed{index,it->
if(index % 3==0) {
var f234=raw[index+1].split("\t")
var r=Order(raw[index].toInt(),f234[0],f234[1].toInt(),f234[2].toDouble(),
sdf.parse(raw[index+2]))
Orders.add(r)
}
}
var result=Orders.sortedByDescending{it.Amount}.sortedBy{it.SellerId}

Koltin não é muito profissional em processamento de dados, e a maioria das funções requer códigos embutidos, incluindo pegar campos por posição e pegar campos de uma coleção de coleções.

Escala:

val raw=spark.read.text("D:/threelines.txt")
val rawrn=raw.withColumn("rn", monotonically_increasing_id())
var f1=rawrn.filter("rn % 3==0").withColumnRenamed("value","OrderId")
var f5=rawrn.filter("rn % 3==2").withColumnRenamed("value","OrderDate")
var f234=rawrn.filter("rn % 3==1")
.withColumn("splited",split(col("value"),"\t"))
.select(col("splited").getItem(0).as("Client")
,col("splited").getItem(1).as("SellerId")
,col("splited").getItem(2).as("Amount"))
f1.withColumn("rn1",monotonically_increasing_id())
f5=f5.withColumn("rn1",monotonically_increasing_id())
f234=f234.withColumn("rn1",monotonically_increasing_id())
var f=f1.join(f234,f1("rn1")===f234("rn1"))
.join(f5,f1("rn1")===f5("rn1"))
.select("OrderId","Client","SellerId","Amount","OrderDate")
val result=f.orderBy(col("SellerId"),-col("Amount"))

Scala é mais especializado em processamento de dados, fazendo uso pesado de funções de computação estruturadas em vez de código de looping escrito. No entanto, o Scala não tem a capacidade de computação ordenada, e as funções relacionadas geralmente precisam ser processadas adicionando uma coluna de número de sequência, resultando em um código geral longo.
SPL:

UMA
1 =file("D:\\data.csv").import@si()
2 =A1.grupo((#-1)\3)
3 =A2.new(~(1):OrderID, (line=~(2).array("\t"))(1):Client,line(2):SellerId,line(3):Amount,~( 3):Data do pedido)
4 =A3.sort(SellerId,-Amount)

A SPL é a mais profissional em processamento de dados e pode atingir metas apenas com funções de cálculo estruturadas. SPL suporta cálculos ordenados, você pode agrupar diretamente por posição, pegar campos por posição e pegar campos de coleções em coleções.Embora a ideia de implementação seja semelhante ao Scala, o código é muito mais curto.

Estrutura do aplicativo

Integração de aplicativos Java

Kotlin é compilado em bytecode, que, como arquivos de classe comuns, pode ser facilmente chamado pelo Java. Por exemplo, o método estático fun multiLines(): List<Order> em KotlinFile.kt será reconhecido corretamente pelo Java e pode ser chamado diretamente:

java.util.List result=KotlinFileKt.multiLines();
result.forEach(e->{System.out.println(e);});

Scala também é bytecode após a compilação, que também pode ser facilmente chamado pelo Java. Por exemplo, o método estático def multiLines():DataFrame do objeto ScalaObject será reconhecido como um tipo Dataset por Java e pode ser chamado com uma pequena modificação:

org.apache.spark.sql.Dataset df=ScalaObject.multiLines();
df.show();

O SPL fornece uma interface JDBC comum e o código SPL simples pode ser incorporado diretamente em Java como o SQL:

Class.forName("com.esproc.jdbc.InternalDriver");
Connection connection =DriverManager.getConnection("jdbc:esproc:local://");
Statement statement = connection.createStatement();
String str="=T(\"D:/Orders.xls\").select(Amount>1000 && Amount<=3000 && like(Client,\"*s*\"))";
ResultSet result = statement.executeQuery(str);

O código SPL complexo pode ser armazenado primeiro como um arquivo de script e, em seguida, chamado pelo Java na forma de um procedimento armazenado, o que pode reduzir efetivamente o acoplamento entre o código de cálculo e o aplicativo front-end.

Class.forName("com.esproc.jdbc.InternalDriver");
Connection conn =DriverManager.getConnection("jdbc:esproc:local://");
CallableStatement statement = conn.prepareCall("{call scriptFileName(?, ?)}");
statement.setObject(1, "2020-01-01");
statement.setObject(2, "2020-01-31");
statement.execute();

SPL é uma linguagem interpretada. Após a modificação, ela pode ser executada diretamente sem compilar. Ela suporta troca de código a quente, o que pode reduzir a carga de trabalho de manutenção e melhorar a estabilidade do sistema. Kotlin e Scala são linguagens compiladas e os aplicativos devem ser reiniciados em algum momento após a compilação.

O código aberto é o espírito de todo programador, todos podem se comunicar e aprender juntos

linha de comando interativa

A linha de comando interativa do Kotlin requer um download adicional, que é iniciado usando o comando Kotlinc. A linha de comando Kotlin teoricamente pode executar processamento de dados arbitrariamente complexo, mas como o código geralmente é longo e difícil de modificar na linha de comando, é mais adequado para cálculos numéricos simples:

>>>Math.sqrt(5.0)
2.236.6797749979

A linha de comando interativa do Scala é integrada, iniciada com o comando de mesmo nome. A linha de comando Scala teoricamente pode realizar o processamento de dados, mas como o código é relativamente longo, é mais adequado para cálculos numéricos simples:

scala>100*3
rest1: Int=300

O SPL possui uma linha de comando interativa integrada, comece com o comando "esprocx -r -c". Os códigos SPL são geralmente mais curtos e permitem a manipulação simples de dados na linha de comando.

(1): T("d:/Orders.txt").groups(SellerId;sum(Amount):amt).select(amt>2000)
(2):^C
D:\raqsoft64\esProc\bin>Log level:INFO
1       4263.900000000001
3       7624.599999999999
4       14128.599999999999
5       26942.4

Informações SPL

Os bancos de dados estão se tornando cada vez mais importantes em nosso uso. Através de várias comparações, podemos ver que para tarefas comuns de processamento de dados no desenvolvimento de aplicativos, Kotlin tem baixa eficiência de desenvolvimento porque não é profissional o suficiente; Scala tem certo profissionalismo e eficiência de desenvolvimento. Kotlin, mas não tão bom quanto SPL; SPL tem sintaxe mais concisa, maior eficiência de expressão, mais tipos de fontes de dados, interfaces mais fáceis, objetos de dados estruturados mais profissionais, funções mais ricas e poder de computação mais forte e desenvolvimento muito mais eficiente. e Escala.

Bem-vindo ao intercâmbio e estudo.

Acho que você gosta

Origin blog.csdn.net/mengchuan6666/article/details/126616736
Recomendado
Clasificación