Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/mercurial/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Apache spark PySpark+Cassandra:获取分区键的不同值_Apache Spark_Cassandra_Pyspark_Spark Cassandra Connector - Fatal编程技术网

Apache spark PySpark+Cassandra:获取分区键的不同值

Apache spark PySpark+Cassandra:获取分区键的不同值,apache-spark,cassandra,pyspark,spark-cassandra-connector,Apache Spark,Cassandra,Pyspark,Spark Cassandra Connector,我试图在pyspark中获取cassandra表的分区键的不同值。然而,pyspark似乎不理解我,完全迭代了大量的所有数据,而不是查询索引 这是我使用的代码,对我来说非常简单: from pyspark.sql import SparkSession spark = SparkSession \ .builder \ .appName("Spark! This town not big enough for the two of us.") \ .getOrCreat

我试图在pyspark中获取cassandra表的分区键的不同值。然而,pyspark似乎不理解我,完全迭代了大量的所有数据,而不是查询索引

这是我使用的代码,对我来说非常简单:

from pyspark.sql import SparkSession

spark = SparkSession \
    .builder \
    .appName("Spark! This town not big enough for the two of us.") \
    .getOrCreate()

ct = spark.read\
    .format("org.apache.spark.sql.cassandra")\
    .options(table="avt_sensor_data", keyspace="ipe_smart_meter")\
    .load()

all_sensors = ct.select("machine_name", "sensor_name")\
    .distinct() \
    .collect()
列machine_name和sensor_name一起构成了分区键,完整的模式见下文。在我看来,这应该是非常快的,事实上,如果我在cql中执行此查询,只需几秒钟:

select distinct machine_name,sensor_name from ipe_smart_meter.avt_sensor_data;
然而,spark的工作需要大约10个小时才能完成。从spark告诉我的计划来看,它似乎真的想迭代所有数据:

== Physical Plan ==
*HashAggregate(keys=[machine_name#0, sensor_name#1], functions=[], output=[machine_name#0, sensor_name#1])
+- Exchange hashpartitioning(machine_name#0, sensor_name#1, 200)
   +- *HashAggregate(keys=[machine_name#0, sensor_name#1], functions=[], output=[machine_name#0, sensor_name#1])
      +- *Scan org.apache.spark.sql.cassandra.CassandraSourceRelation@2ee2f21d [machine_name#0,sensor_name#1] ReadSchema: struct<machine_name:string,sensor_name:string>

似乎只有在选择、筛选或排序时,cassandra服务器端自动下推谓词才会起作用

所以,对于distinct,spark获取所有行,然后执行distinct

解决方案1 你说你的cql选择不同的。。。已经是超快了。我猜分区键的数量相对较少,包括machine_name和sensor_name的组合以及如此多的“ts”

所以,最简单的解决方案就是以cql为例

解决方案2 由于cassandra是一个查询优先的数据库,所以只需再创建一个表,该表只包含独特查询所需的分区键

CREATE TABLE ipe_smart_meter.avt_sensor_name_machine_name (
    machine_name text,
    sensor_name text,
    PRIMARY KEY ((machine_name, sensor_name))
);
然后,每次在原始表中插入一行时,都要在新表中插入机器名称和传感器名称。 因为它只有分区键,所以对于查询来说,这是一个自然的不同表。把所有的行都记下来。也许超快。不需要区分过程

解决方案3 我认为解决方案2是最好的。但如果您不想对一条记录执行两次插入,另一种解决方案是更改表并创建一个物化视图表

CREATE TABLE ipe_smart_meter.ipe_smart_meter.avt_sensor_data (
    machine_name text,
    sensor_name text,
    ts timestamp,
    id bigint,
    value double,
    dist_hint_num smallint,
    PRIMARY KEY ((machine_name, sensor_name), ts)
) WITH CLUSTERING ORDER BY (ts DESC)
;

CREATE MATERIALIZED VIEW IF NOT EXISTS ipe_smart_meter.avt_sensor_data_mv AS
  SELECT
    machine_name
    ,sensor_name
    ,ts
    ,dist_hint_num
  FROM ipe_smart_meter.avt_sensor_data
  WHERE
    machine_name IS NOT NULL
    AND sensor_name IS NOT NULL
    AND ts IS NOT NULL
    AND dist_hint_num IS NOT NULL
  PRIMARY KEY ((dist_hint_num), machine_name, sensor_name, ts)
  WITH
  AND CLUSTERING ORDER BY (machine_name ASC, sensor_name DESC, ts DESC)
;
dist_hint_num列用于限制查询要迭代和分发记录的分区总数

例如,从0到15。Random integer Random.randint0、15或基于哈希的整数哈希函数机器名+传感器名%16正常。 然后,当您进行如下查询时。cassandra只从16个分区获取所有记录,这可能比您当前的情况更有效

但是,无论如何,所有的记录都必须被读取,然后发生不同的洗牌。不节省空间。我认为这不是一个好的解决办法

functools.reduce(
    lambda df, dist_hint_num: df.union(
        other=spark_session.read.format(
            'org.apache.spark.sql.cassandra',
        ).options(
            keyspace='ipe_smart_meter',
            table='avt_sensor_data_mv',
        ).load().filter(
            col('dist_hint_num') == expr(
                f'CAST({dist_hint_num} AS SMALLINT)'
            )
        ).select(
            col('machine_name'),
            col('sensor_name'),
        ),
    ),
    range(0, 16),
    spark_session.createDataFrame(
        data=(),
        schema=StructType(
            fields=(
                StructField(
                    name='machine_name',
                    dataType=StringType(),
                    nullable=False,
                ),
                StructField(
                    name='sensor_name',
                    dataType=StringType(),
                    nullable=False,
                ),
            ),
        ),
    ),
).distinct().persist().alias(
    'df_all_machine_sensor',
)

谢谢,我实际上使用了解决方案1,因为我没有对该数据库的写访问权。
functools.reduce(
    lambda df, dist_hint_num: df.union(
        other=spark_session.read.format(
            'org.apache.spark.sql.cassandra',
        ).options(
            keyspace='ipe_smart_meter',
            table='avt_sensor_data_mv',
        ).load().filter(
            col('dist_hint_num') == expr(
                f'CAST({dist_hint_num} AS SMALLINT)'
            )
        ).select(
            col('machine_name'),
            col('sensor_name'),
        ),
    ),
    range(0, 16),
    spark_session.createDataFrame(
        data=(),
        schema=StructType(
            fields=(
                StructField(
                    name='machine_name',
                    dataType=StringType(),
                    nullable=False,
                ),
                StructField(
                    name='sensor_name',
                    dataType=StringType(),
                    nullable=False,
                ),
            ),
        ),
    ),
).distinct().persist().alias(
    'df_all_machine_sensor',
)