如何在多个键列上按范围搜索? 我看到的方式我们不能有一个可能会转到多个分区的查询。 任何可能的解决方案来实现相同的查询结果???
CREATE TABLE RangeSearch (segment TEXT, date TIMESTAMP, dec decimal, value text, PRIMARY KEY (segment,date,dec));
SELECT * FROM decimalrangeck
WHERE segment='SEG1'
AND date>='2015-01-01' AND date<='2015-12-12';
AND dec>=100 AND dec<=200;
答案 0 :(得分:1)
简短回答:无法对Cassandra中的两个或更多聚类列进行有效范围查询。
答案很长:要了解此限制的核心原因,您应该考虑Cassandra如何将列存储在单个分区中。
单个SSTable文件中分区内的所有行都根据其聚类键进行排序,例如您的架构:
2015-01-01 100
2015-01-01 200
2015-01-01 300
2015-01-02 100
2015-01-02 200
2015-01-02 300
2015-01-03 100
有一种方法可以读取单个数据片段(通过使用范围查询,如SELECT * FROM decimalrangeck WHERE segment='SEG1' AND date>='2015-01-01' AND date<'2015-01-03';
)。对于此查询,Cassandra将为行发出单个磁盘搜索,因为它肯定知道所需数据的开始和结束位置(因为它在磁盘上排序)。
您甚至可以使用SELECT * FROM decimalrangeck WHERE segment='SEG1' AND date>='2015-01-01' AND date<'2015-01-03' AND dec>=100 AND dec<=200
这样的双列切片查询。我相信你会期待这些结果:
2015-01-01 100
2015-01-01 200
2015-01-02 100
2015-01-02 200
但是你会得到一个稍微令人惊讶的输出:
2015-01-01 100
2015-01-01 200
2015-01-01 300
2015-01-02 100
2015-01-02 200
差异是一行2015-01-01 300
。它出现在输出中有一个原因:您的查询分为两部分:切片的开始(2015-01-01,100)和切片的结束(2015-03-01,100)。之后,Cassandra在单个磁盘搜索中读取这些数据点之间的所有数据。
2个群集列的原始范围查询将需要太多的磁盘读取才能完成。此类查询通常被认为对性能不友好。
答案 1 :(得分:0)
是的,您可以spark使用scala和spark-cassandra-connector来执行此操作!
然后你可以使用类似的东西:
val conf = new SparkConf().setAppName(appName)
val sc = new SparkContext(conf)
val sqlContext = new SQLContext(sc)
val cc = new CassandraSQLContext(sc)
def getDays(startDate: String, endDate: String) : scala.Array[String] = {
var dates = scala.Array[String]()
var sDate = sdfDay.parseDateTime(startDate)
var eDate = sdfDay.parseDateTime(endDate)
var date = ""
while(sDate.isBefore(eDate.plusDays(1)) == true){
var sDay = sDate.getDayOfMonth()
var sMonth = sDate.getMonthOfYear()
var sYear = sDate.getYear()
date = "" + sYear + "-" + sMonth + "-" + sDay
println(date)
dates :+= date
sDate = sDate.plusDays(1)
}
dates //return
}
def preaperQuery(wereElement: String, andDateElement: String, andDecElement: String, tableName: String, days: scala.Array[String], decs: scala.Array[String]) : String = {
var q = "select * from " + tableName + "where " + wereElement + " and "
for (day <- days) {
q = q + andDateElement + " = '" + day + "' or "
}
for (dec <- decs) {
q = q + andDecElement + " = '" + dec + "' or "
}
//remove last " or " 4 chars
q = q.dropRight(4)
q //return
}
val days = Utils.getDays(startDate, endDate)
val decs = Array("100", "200", "300", "400") //or any function
var q = Utils.preaperQuery(wereElement="segment='SEG1'", andDateElement="date", andDecElement="ec", tableName="RangeSearch", days=days, decs=decs)
val selected_data = cc.sql(q).map(row => (row(0).toString, row(1).toString,row(2).toString,row(3).toString))
您可以收集所选的数据rdd:
val data = selected_data.collect
我有similar problem ...