您将如何在PySpark中使用和/或实现等效的案例类?
正如Alex
Hall[所提到的,命名产品类型的真实等效项是namedtuple
。
与Row
在其他答案中建议的不同,它具有许多有用的属性:
>>> from collections import namedtuple
FooBar = namedtuple(“FooBar”, [“foo”, “bar”])
foobar = FooBar(42, -42)
foo, bar = foobar
foo
42
bar
-42
相反Rows
,与关键字参数一起使用时并不可靠:
>>> from pyspark.sql import Row
>>>
>>> foobar = Row(foo=42, bar=-42)
>>> foo, bar = foobar
>>> foo
-42
>>> bar
42
尽管如果使用位置参数定义:
>>> FooBar = Row("foo", "bar")
>>> foobar = FooBar(42, -42)
>>> foo, bar = foobar
>>> foo
42
>>> bar
-42
订单被保留。
>>> from functools import singledispatch
FooBar = namedtuple(“FooBar”, [“foo”, “bar”])
type(FooBar)
isinstance(FooBar(42, -42), FooBar)
True
可以在需要类型处理的任何地方使用,尤其是对于单个:
>>> Circle = namedtuple("Circle", ["x", "y", "r"])
>>> Rectangle = namedtuple("Rectangle", ["x1", "y1", "x2", "y2"])
>>>
>>> @singledispatch
... def area(x):
... raise NotImplementedError
...
...
>>> @area.register(Rectangle)
... def _(x):
... return abs(x.x1 - x.x2) * abs(x.y1 - x.y2)
...
...
>>> @area.register(Circle)
... def _(x):
... return math.pi * x.r ** 2
...
...
>>>
>>> area(Rectangle(0, 0, 4, 4))
16
>>> >>> area(Circle(0, 0, 4))
50.26548245743669
和多个调度:
>>> from multipledispatch import dispatch
>>> from numbers import Rational
>>>
>>> @dispatch(Rectangle, Rational)
... def scale(x, y):
... return Rectangle(x.x1, x.y1, x.x2 * y, x.y2 * y)
...
...
>>> @dispatch(Circle, Rational)
... def scale(x, y):
... return Circle(x.x, x.y, x.r * y)
...
...
>>> scale(Rectangle(0, 0, 4, 4), 2)
Rectangle(x1=0, y1=0, x2=8, y2=8)
>>> scale(Circle(0, 0, 11), 2)
Circle(x=0, y=0, r=22)
并结合第一个属性,可以在广泛的模式匹配场景中使用。namedtuples
还支持标准继承和类型提示。
Rows
别:
>>> FooBar = Row("foo", "bar")
>>> type(FooBar)
<class 'pyspark.sql.types.Row'>
>>> isinstance(FooBar(42, -42), FooBar) # Expected failure
Traceback (most recent call last):
...
TypeError: isinstance() arg 2 must be a type or tuple of types
>>> BarFoo = Row("bar", "foo")
>>> isinstance(FooBar(42, -42), type(BarFoo))
True
>>> isinstance(BarFoo(42, -42), type(FooBar))
True
Row
对象不同,元组不在__dict__
每个实例中使用和携带字段名称。结果,初始化可以快几个数量级:>>> FooBar = namedtuple("FooBar", ["foo", "bar"])
%timeit FooBar(42, -42)
587 ns ± 5.28 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
与不同的Row
构造函数相比:
>>> %timeit Row(foo=42, bar=-42)
3.91 µs ± 7.67 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
>>> FooBar = Row("foo", "bar")
>>> %timeit FooBar(42, -42)
2 µs ± 25.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
并且显着提高了内存效率(在处理大规模数据时,这是非常重要的属性):
>>> import sys
>>> FooBar = namedtuple("FooBar", ["foo", "bar"])
>>> sys.getsizeof(FooBar(42, -42))
64
与同等相比 Row
>>> sys.getsizeof(Row(foo=42, bar=-42))
72
最后,使用以下命令可以更快地访问属性namedtuple
:
>>> FooBar = namedtuple("FooBar", ["foo", "bar"])
>>> foobar = FooBar(42, -42)
>>> %timeit foobar.foo
102 ns ± 1.33 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
与Row
对象的等效操作相比:
>>> foobar = Row(foo=42, bar=-42)
>>> %timeit foobar.foo
2.58 µs ± 26.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
namedtuples
的一点在Spark SQL中得到正确支持>>> Record = namedtuple("Record", ["id", "name", "value"])
spark.createDataFrame([Record(1, “foo”, 42)])
DataFrame[id: bigint, name: string, value: bigint]
总结 :
应该清楚的Row
是,它不能真正替代实际的产品类型,并且应避免使用,除非由Spark
API强制执行。
还应该清楚的pyspark.sql.Row
是,当您考虑到它不是case类的替代品时,它直接等效于-
type,它与org.apache.spark.sql.Row
实际产品相差很远,并且其行为类似于Seq[Any]
(取决于子类,并添加了名称)
)。引入Python和Scala实现都是有用的,尽管外部代码和内部Spark SQL表示形式之间的接口笨拙。
另请参阅 :
>>> import macropy.console
0=[]=====> MacroPy Enabled <=====[]=0
from macropy.case_classes import macros, case
@case
… class FooBar(foo, bar): pass
…
foobar = FooBar(42, -42)
foo, bar = foobar
foo
42
bar
-42
它具有许多其他功能,包括但不限于高级模式匹配和简洁的lambda表达式语法。
dataclasses
(Python 3.7+)。问题内容: 是否有关于何时使用案例类(或案例对象)与扩展Scala中的枚举的最佳实践指南? 他们似乎提供了一些相同的好处。 问题答案: 最大的不同是Enumerations支持从某些nameString实例化它们。例如: 然后,您可以执行以下操作: 当希望保留枚举(例如,到数据库)或根据文件中的数据创建枚举时,此功能很有用。但是,我发现总体上来说,枚举在Scala中有点笨拙,并且具有附加组件的尴尬
如何只在pos时返回case类
我正在使用Scala编写Play 2.5应用程序。我有下面这段代码: 我还有一个控制器,我也在其中注入了 BarRepository,但是通过构造函数,在 val a barRepository.bar= 的类 Foo 中,我得到一个 NullPointerException,一切都运行良好。有人可以帮助找出问题所在吗?是否禁止在案例类中使用注射?
问题内容: 我试图将一些Scala代码注入到现有的Java应用程序中。(所以,话说回来,我想要更多的乐趣)。 我在Scala中创建一个单例的东西 现在,在OldJava.java中 我应该填写什么以便Java调用showMyPower方法?我尝试了两者 ,但没有任何效果。 (使用Jad反编译类文件,除了胡说八道之外,什么都没给我显示。) 编辑 我删除了声明,scala产生了预期的静态方法。(呼吁工
大家好,我在SCALA上创建了以下案例类: 然后,如您所见,BGP包含Term并扩展到模式,Val包含值并扩展到Term,U、L、B包含字符串并扩展到Value,在我的函数中,我想访问包含U或L或B大小写类的字符串,变量valor=Val(y). value包含一个U类,例如,但当我编写valor时。XXXX没有给我显示名称选项。最大的问题是如何从U访问字符串名称?
问题内容: Java中的类,对象和实例是什么? 问题答案: Java(和任何其他编程语言)是根据类型和值建模的。从理论上讲,值是某种信息量的表示,类型是一组值。当我们说值X 是类型Y 的实例时,我们只是说X是类型Y的值集合的成员。 这就是“实例”一词的真正含义:它描述的是一种关系而不是事物。 Java编程语言的类型系统支持两种类型,原始类型和引用类型。引用类型进一步分为类和数组类型。Java 对象