在Spark sql

时间:2017-12-20 09:29:21

标签: java apache-spark apache-spark-sql spark-dataframe

我有一个字段代表我的架构中的IP地址。我想使用Binary Type来存储数据。

我想象的方式是,如果我的ip是:50.100.150.200我将它保存为[50,100,150,200]字节数组(序列肯定很重要,但我们可以将其排除在此问题的讨论之外)。

我的问题是如何在查询时按此列进行过滤? (字符串并不真正符合目的)

例如,我想运行以下查询:

SELECT * from table1 WHERE sourceip='50.100.150.200'

以下是一段用于演示此问题的代码:

Bean定义(用于模式创建):

    public static class MyBean1 implements Serializable {
    private static final long serialVersionUID = 1L;
    private int id;
    private String name;
    private byte[] description;

    public MyBean1(int id, String name, String description) {
        this.id = id;
        this.name = name;
        this.description = description.getBytes();
    }

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public byte[] getDescription() {
        return description;
    }
    public void setDescription(byte[] description) {
        this.description = description;
    }
}

演示代码(我想按说明进行过滤):

    List<MyBean1> newDebugData = new ArrayList<MyBean1>();
    newDebugData.add(new MyBean1(1, "Arnold", "10.150.15.10"));
    newDebugData.add(new MyBean1(1, "Bob", "10.150.15.11"));
    newDebugData.add(new MyBean1(3, "Bob", "10.150.15.12"));
    newDebugData.add(new MyBean1(3, "Bob", "10.150.15.13"));
    newDebugData.add(new MyBean1(1, "Alice", "10.150.15.14"));

    Dataset<Row> df2 = sqlContext.createDataFrame(newDebugData, MyBean1.class);
    df2.createTempView("table1");
    sqlContext.sql("select * from table1 where description='10.150.15.14'").show();

我收到错误:

differing types in '(table1.`description` = CAST('10.150.15.14' AS DOUBLE))'

2 个答案:

答案 0 :(得分:0)

这不是你问题的100%答案,但我希望指针有所帮助。

以下问题不是关于过滤,而是选择数组中的数据。 selecting a range of elements in an array spark sql

它看起来像很多信息,包括UDF使用Spark SQL查询数组的一些指导。

希望这有帮助。

答案 1 :(得分:0)

SPARK-21344在版本2.0.3、2.1.2和2.2.1中修复了以下问题:BinaryType比较不会对有符号字节数组进行比较。因此,二进制比较应该适用于这些版本。

JIRA具有以下scala测试代码:

case class TestRecord(col0: Array[Byte])
def convertToBytes(i: Long): Array[Byte] = {
   val bb = java.nio.ByteBuffer.allocate(8)
   bb.putLong(i)
   bb.array
}
val timestamp = 1498772083037L
val data = (timestamp to timestamp + 1000L).map(i => TestRecord(convertToBytes(i)))
val testDF = sc.parallelize(data).toDF
val filter1 = testDF.filter(col("col0") >= convertToBytes(timestamp) 
              && col("col0") < convertToBytes(timestamp + 50L))
assert(filter1.count == 50)

我不知道等效的Java代码是什么,但这应该可以帮助您入门。


我在上面的评论中提到我们使用LongType存储IPv4地址的问题。我们有一个包装器脚本,可将点分十进制转换为长整数,而Spark UDF则采用另一种方式:将长整数转换为点分十进制。我认为LongType的查询比BinaryType更快。