Cet article vous apporte des connaissances pertinentes sur java, qui présente principalement les problèmes liés à la bibliothèque open source de traitement de données structurées SPL. Jetons un coup d'œil à la bibliothèque de traitement de données structurées idéale sous Java.
Étude recommandée : "Tutoriel vidéo Java"
L'architecture d'application Java moderne met de plus en plus l'accent sur la séparation du stockage et du traitement des données pour obtenir une meilleure maintenabilité, évolutivité et portabilité, comme les Fiery Microservices en sont un exemple typique. Cette architecture nécessite généralement que la logique métier soit implémentée dans les programmes Java au lieu d'être placée dans la base de données comme dans l'architecture d'application traditionnelle.
La plupart de la logique métier des applications implique un traitement de données structuré. La base de données (SQL) offre un support riche pour de telles tâches et la logique métier peut être mise en œuvre relativement facilement. Cependant, Java a toujours manqué d'un tel support de base, ce qui rend la mise en œuvre de la logique métier en Java très lourde et inefficace. En conséquence, malgré divers avantages architecturaux, l’efficacité du développement a considérablement diminué.
Si nous fournissons également un ensemble complet de bibliothèques de classes structurées de traitement de données et de calcul en Java, alors ce problème peut être résolu : profiter des avantages de l'architecture sans réduire l'efficacité du développement.
Quelles caractéristiques doit avoir une bibliothèque idéale de traitement de données structurées sous Java ? Nous pouvons résumer à partir de SQL :
Les données structurées apparaissent souvent par lots (sous forme d'ensembles). Afin de calculer facilement ce type de données, il est nécessaire de fournir des capacités de calcul d'ensemble suffisantes.
S'il n'y a pas de bibliothèque d'opérations d'ensemble, il n'y a que le type de données de base du tableau (équivalent à un ensemble). Si nous voulons simplement additionner les membres de l'ensemble, nous devons écrire quatre ou cinq lignes d'instructions de boucle pour le compléter. Les opérations telles que le filtrage, le regroupement et l'agrégation représentent des centaines de lignes de code à écrire.
SQL fournit un riche ensemble d'opérations, telles que SUM/COUNT et d'autres opérations d'agrégation, WHERE est utilisé pour le filtrage, GROUP est utilisé pour le regroupement, et il prend également en charge les opérations de base telles que l'intersection, l'union et la différence pour les ensembles. Le code écrit de cette manière sera beaucoup plus court.
Est-il suffisant d'avoir des capacités de fonctionnement définies ? Si nous développons un lot de bibliothèques d'opérations d'ensemble pour Java, pouvons-nous obtenir l'effet de SQL ?
Ce n’est pas si simple !
Prenons l'opération de filtrage comme exemple. Le filtrage nécessite généralement une condition pour conserver les membres de l'ensemble qui remplissent la condition. En SQL, cette condition apparaît sous la forme d'une expression. Par exemple, écrire WHERE x>0 signifie conserver les membres qui rendent le résultat du calcul x>0 vrai. L'expression x>0 n'est pas évaluée avant l'exécution de cette instruction, mais est évaluée pour chaque membre de l'ensemble lors de l'itération. Essentiellement, cette expression est essentiellement une fonction, une fonction qui prend les membres de la collection actuelle comme paramètres. Pour l'opération WHERE, cela équivaut à utiliser une fonction définie avec une expression comme paramètre de WHERE.
Il existe un terme pour cette façon d'écrire appelé syntaxe Lambda, ou langage fonctionnel.
Sans la syntaxe Lambda, nous devrions souvent définir temporairement des fonctions, ce qui rendrait le code très lourd et sujet aux conflits de noms.
La syntaxe Lambda est largement utilisée en SQL. Elle n'est pas requise pour les opérations de filtrage et de regroupement. Elle peut également être utilisée dans des scénarios inutiles tels que les colonnes calculées, ce qui simplifie grandement le code.
Les données structurées ne sont pas une simple valeur unique, mais un enregistrement avec des champs.
Nous avons constaté que lors du référencement de champs d'enregistrement dans les paramètres d'expression SQL, dans la plupart des cas, vous pouvez utiliser le nom du champ directement sans spécifier l'enregistrement auquel le champ appartient. Ce n'est que lorsqu'il existe plusieurs champs portant le même nom que vous devez utiliser le. nom de la table (ou alias).
Bien que la nouvelle version de Java ait également commencé à prendre en charge la syntaxe Lambda, elle ne peut transmettre que l'enregistrement actuel en tant que paramètre dans la fonction définie avec la syntaxe Lambda, puis toujours apporter cet enregistrement lors de l'écriture des formules de calcul. Par exemple, lors du calcul du montant en utilisant le prix unitaire et la quantité, si le paramètre utilisé pour représenter le membre actuel est nommé x, il doit être écrit sous la forme longue de « x. prix unitaire * x. quantité ». En SQL, il peut être écrit de manière plus intuitive sous la forme « prix unitaire * quantité ».
SQL peut également très bien prendre en charge les structures de données dynamiques.
Dans les calculs de données structurées, la valeur de retour est souvent des données structurées, et la structure des données de résultat est liée aux opérations et ne peut pas être préparée avant d'écrire le code. Il est donc nécessaire de prendre en charge les capacités de structure de données dynamique.
Toute instruction SELECT en SQL générera une nouvelle structure de données, et des champs pourront être ajoutés et supprimés dans le code sans avoir à définir la structure (classe) à l'avance. Cela n'est pas possible avec des langages comme Java. Toutes les structures (classes) utilisées doivent être définies lors de la phase de compilation du code, en principe, de nouvelles structures ne peuvent pas être générées dynamiquement lors de l'exécution.
De l'analyse des articles précédents, nous pouvons déjà conclure que Java lui-même n'est pas adapté comme langage pour le traitement de données structurées. Son mécanisme Lambda ne prend pas en charge la fonctionnalité 3 et, en tant que langage compilé, il ne peut pas implémenter la fonctionnalité 4.
En fait, la syntaxe Lambda mentionnée précédemment n'est pas adaptée à une implémentation dans les langages compilés. Le compilateur ne peut pas déterminer si l'expression écrite à la position du paramètre doit calculer la valeur de l'expression sur place puis la transmettre, ou compiler l'expression entière dans une fonction et la transmettre, et davantage de symboles de syntaxe doivent être conçus pour distinguer il. Les langages interprétés n'ont pas ce problème. La fonction elle-même peut décider si l'expression en tant que paramètre est calculée en premier ou après avoir parcouru les membres de la collection.
SQL est en effet un langage interprété.
Stream est une bibliothèque de traitement de données structurées officiellement lancée en Java 8, mais elle ne répond pas aux exigences ci-dessus. Il ne dispose pas de types de données structurés professionnels, manque de nombreuses fonctions importantes de calcul de données structurées, n'est pas un langage interprété, ne prend pas en charge les types de données dynamiques et l'interface de la syntaxe Lambda est complexe.
Kotlin fait partie de l'écosystème Java. Il a apporté de légères améliorations basées sur Stream et fournit également des types de calcul de données structurées. Cependant, en raison de fonctions de calcul de données structurées insuffisantes, ce n'est pas un langage interprété et ne prend pas en charge les données dynamiques. .Type, l'interface de la syntaxe Lambda est complexe et ce n'est toujours pas une bibliothèque de classes de calcul de données structurées idéale.
Scala fournit un riche ensemble de fonctions de calcul de données structurées, mais les caractéristiques des langages compilés l'empêchent également de devenir une bibliothèque de classes de calcul de données structurées idéale.
Alors, que peut-on utiliser d'autre dans l'écosystème Java ?
esProc SPL.
SPL est un langage de programmation interprété et exécuté par Java. Il possède une riche bibliothèque de classes de calcul de données structurées, une syntaxe Lambda simple et des structures de données dynamiques pratiques et faciles à utiliser.
SPL fournit un type de données structurées professionnelles, à savoir une table de séquence. Comme la table de données SQL, la table de séquence est une collection d'enregistrements par lots et possède les fonctions générales des types de données structurés. Voici un exemple.
Analysez les données source et générez une table de séquence :
Orders=T("d:/Orders.csv")
Générez une nouvelle table de séquence à partir de la table de séquence d'origine par nom de colonne :
Orders.new(OrderID, Amount, OrderDate)
Colonne calculée :
Orders.new(OrderID, Amount, year(OrderDate))
Renommer le champ :
Orders.new(OrderID:ID, SellerId, year(OrderDate):y)
Utiliser les champs par numéro de séquence :
Orders.groups(year(_5),_2; sum(_4))
Renommer la table de séquence (association gauche)
join@1(Orders:o,SellerId ; Employees:e,EId).groups(e.Dept; sum(o.Amount))
La table de séquence prend en charge toutes les fonctions de calcul structurées, et le résultat du calcul est également une table de séquence, pas un type de données tel que Map. Par exemple, continuez à traiter des données structurées pour des résultats récapitulatifs groupés :
Orders.groups(year(OrderDate):y; sum(Amount):m).new(y:OrderYear, m*0.2:discount)
Basé sur la table de séquence, SPL fournit une multitude de fonctions de calcul de données structurées, telles que le filtrage, le tri, le regroupement, la déduplication, le renommage, les colonnes calculées, les associations, les sous-requêtes. , définir des calculs, des calculs ordonnés, etc. Ces fonctions ont de puissantes capacités informatiques et peuvent effectuer des calculs indépendamment sans assistance codée en dur :
Requête combinée :
Orders.select(Amount>1000 && Amount<=3000 && like(Client,"*bro*"))
Tri :
Orders.sort(-Client,Amount)
Résumé du groupe :
Orders.groups(year(OrderDate),Client; sum(Amount))
Association interne :
join(Orders:o,SellerId ; Employees:e,EId).groups(e.Dept; sum(o.Amount))
SPL prend en charge la syntaxe Lambda simple. Il n'est pas nécessaire de définir des noms de fonction et des corps de fonction. Les expressions peuvent être directement utilisées comme paramètres de fonction, comme le filtrage :
Orders.select(Amount>1000)
Lors de la modification de la logique métier, il n'est pas nécessaire de reconstruire la fonction, il suffit de la modifier. l'expression :
Orders.select(Amount>1000 && Amount<2000)
SPL est un langage interprété lors de l'utilisation d'expressions de paramètres, il n'est pas nécessaire de définir explicitement les types de paramètres, ce qui simplifie l'interface Lambda. Par exemple, si vous souhaitez calculer la somme des carrés, vous pouvez l'écrire intuitivement :
Orders.sum(Amount*Amount)
Semblable à SQL, la syntaxe SPL prend également en charge l'utilisation directe des noms de champs dans les calculs à table unique :
Orders.sort(-Client, Amount)
SPL C'est un langage interprété qui prend naturellement en charge les structures de données dynamiques et peut générer dynamiquement de nouvelles tables de séquence basées sur la structure des résultats du calcul. Il est particulièrement adapté aux calculs tels que les colonnes calculées, le résumé de groupe et la corrélation. Par exemple, recalculer directement les résultats du résumé de groupe :
Orders.groups(Client;sum(Amount):amt).select(amt>1000 && like(Client,"*S*"))
ou recalculer directement les résultats du calcul de corrélation :
join(Orders:o,SellerId ; Employees:e,Eid).groups(e.Dept; sum(o.Amount))
Des calculs plus complexes doivent généralement être effectués. divisé en plusieurs étapes, la structure des données de chaque résultat intermédiaire est presque différente. SPL prend en charge les structures de données dynamiques sans avoir à définir au préalable la structure de ces résultats intermédiaires. Par exemple, sur la base du tableau des enregistrements de paiement des clients d'une certaine année, calculez les 10 principaux clients avec le montant du paiement mensuel :
Sales2021.group(month(sellDate)).(~.groups(Client;sum(Amount):sumValue)).(~.sort(-sumValue)) .(~.select(#<=10)).(~.(Client)).isect()
SPL implémente également un interpréteur SQL, qui peut être exécuté directement. SQL prend en charge tout, depuis les bases WHERE et GROUP jusqu'à JOIN et même AVEC :
$select * from d:/Orders.csv where (OrderDate<date('2020-01-01') and Amount<=100)or (OrderDate>=date('2020-12-31') and Amount>100)
$select year(OrderDate),Client ,sum(Amount),count(1) from d:/Orders.csv group by year(OrderDate),Client having sum(Amount)<=100
$select o.OrderId,o.Client,e.Name e.Dept from d:/Orders.csv o join d:/Employees.csv e on o.SellerId=e.Eid
$with t as (select Client ,sum(amount) s from d:/Orders.csv group by Client) select t.Client, t.s, ct.Name, ct.address from t left join ClientTable ct on t.Client=ct.Client
En tant que langage professionnel de traitement de données structurées, SPL couvre non seulement toutes les capacités informatiques de SQL, mais en termes de langage, il a également plus avantages puissants :
La collection est une fonctionnalité de base de SQL, qui prend en charge les données pour participer aux opérations sous la forme d'un ensemble. Cependant, la nature discrète de SQL est très médiocre. Tous les membres de l'ensemble doivent participer à l'opération dans son ensemble et ne peuvent être séparés de l'ensemble. Les langages de haut niveau tels que Java prennent en charge une bonne discrétion et les membres du tableau peuvent fonctionner indépendamment.
但是,更彻底的集合化需要离散性来支持,集合成员可以游离在集合之外,并与其它数据随意构成新的集合参与运算 。
SPL兼具了SQL的集合化和Java的离散性,从而可以实现更彻底的集合化。
比如,SPL中很容易表达“集合的集合”,适合分组后计算。比如,找到各科成绩均在前10名的学生:
A | |
---|---|
1 | =T(“score.csv”).group(subject) |
2 | =A2.(.rank(score).pselect@a(<=10)) |
3 | =A1.(~(A3(#)).(name)).isect() |
SPL序表的字段可以存储记录或记录集合,这样可以用对象引用的方式,直观地表达关联关系,即使关系再多,也能直观地表达。比如,根据员工表找到女经理下属的男员工: |
Employees.select(性别:"男",部门.经理.性别:"女")
有序计算是离散性和集合化的典型结合产物,成员的次序在集合中才有意义,这要求集合化,有序计算时又要将每个成员与相邻成员区分开,会强调离散性。SPL兼具集合化和离散性,天然支持有序计算。
具体来说,SPL可以按绝对位置引用成员,比如,取第3条订单可以写成Orders(3),取第1、3、5条记录可以写成Orders([1,3,5])。
SPL也可以按相对位置引用成员,比如,计算每条记录相对于上一条记录的金额增长率:Orders.derive(amount/amount[-1]-1)
SPL还可以用#代表当前记录的序号,比如把员工按序号分成两组,奇数序号一组,偶数序号一组:Employees.group(#%2==1)
大量功能强大的结构化数据计算函数,这本来是一件好事,但这会让相似功能的函数不容易区分。无形中提高了学习难度。
SPL提供了特有的函数选项语法,功能相似的函数可以共用一个函数名,只用函数选项区分差别。比如select函数的基本功能是过滤,如果只过滤出符合条件的第1条记录,只须使用选项@1:
Orders.select@1(Amount>1000)
数据量较大时,用并行计算提高性能,只须改为选项@m:
Orders.select@m(Amount>1000)
对排序过的数据,用二分法进行快速过滤,可用@b:
Orders.select@b(Amount>1000)
函数选项还可以组合搭配,比如:
Orders.select@1b(Amount>1000)
结构化运算函数的参数常常很复杂,比如SQL就需要用各种关键字把一条语句的参数分隔成多个组,但这会动用很多关键字,也使语句结构不统一。
SPL支持层次参数,通过分号、逗号、冒号自高而低将参数分为三层,用通用的方式简化复杂参数的表达:
join(Orders:o,SellerId ; Employees:e,EId)
普通的Lambda语法不仅要指明表达式(即函数形式的参数),还必须完整地定义表达式本身的参数,否则在数学形式上不够严密,这就让Lambda语法很繁琐。比如用循环函数select过滤集合A,只保留值为偶数的成员,一般形式是:
A.select(f(x):{x%2==0} )
这里的表达式是x%2==0,表达式的参数是f(x)里的x,x代表集合A里的成员,即循环变量。
SPL用固定符号~代表循环变量,当参数是循环变量时就无须再定义参数了。在SPL中,上面的Lambda语法可以简写作:A.select(~ %2==0)
普通Lambda语法必须定义表达式用到的每一个参数,除了循环变量外,常用的参数还有循环计数,如果把循环计数也定义到Lambda中,代码就更繁琐了。
SPL用固定符号#代表循环计数变量。比如,用函数select过滤集合A,只保留序号是偶数的成员,SPL可以写作:A.select(# %2==0)
相对位置经常出现在难度较大的计算中,而且相对位置本身就很难计算,当要使用相对位置时,参数的写法将非常繁琐。
SPL用固定形式[序号]代表相对位置:
A | B | |
---|---|---|
1 | =T(“Orders.txt”) | /订单序表 |
2 | =A1.groups(year(Date):y,month(Date):m; sum(Amount):amt) | /按年月分组汇总 |
3 | =A2.derive(amt/amt[-1]:lrr, amt[-1:1].avg():ma) | /计算比上期和移动平均 |
作为用Java解释的脚本语言,SPL提供了JDBC驱动,可以无缝集成进Java应用程中。
简单语句可以像SQL一样直接执行:
… Class.forName("com.esproc.jdbc.InternalDriver"); Connection conn =DriverManager.getConnection("jdbc:esproc:local://"); PrepareStatement st = conn.prepareStatement("=T(\"D:/Orders.txt\").select(Amount>1000 && Amount<=3000 && like(Client,\"*S*\"))"); ResultSet result=st.execute(); ...
复杂计算可以存成脚本文件,以存储过程方式调用
… Class.forName("com.esproc.jdbc.InternalDriver"); Connection conn =DriverManager.getConnection("jdbc:esproc:local://"); Statement st = connection.(); CallableStatement st = conn.prepareCall("{call splscript1(?, ?)}"); st.setObject(1, 3000); st.setObject(2, 5000); ResultSet result=st.execute(); ...
将脚本外置于Java程序,一方面可以降低代码耦合性,另一方面利用解释执行的特点还可以支持热切换,业务逻辑变动时只要修改脚本即可立即生效,不像使用Java时常常要重启整个应用。这种机制特别适合编写微服务架构中的业务处理逻辑。
推荐学习:《java视频教程》
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!