流計算場景里distinct很常用,spark sql對 stream dataset不支持 SELECT COUNT(DISTINCT Company) FROM Orders
這種用法,但是dataframe支持dropDuplicates,可以指定columns。下面要加上dropDuplicates的操作。
通過et可以實現對dataframe的操作
register語法
register的語法是這樣的:
REGISTER format '.' path as functionName where? expression? booleanExpression*
比如:register ScriptUDF.
scriptTableas plusFun
注冊一個udf
那參考這個語法,我想要對tablex去重,命令應該是:
register DistinctExt.
tablexas tbx where inputTable="{}" and columns="{}"
as語句是語法要求,后面的tbx其實沒有用處。
register語法的原理
通過debug會發現,format
是DistinctExt
,path
是tablex
,option
是where
后面的配置項們
mlsql設計的ET
是要實現一個SQLAlg
接口:
這些接口起的名字似乎都跟機器學習有關,訓練,預測,模型之類的,哈哈,個人感覺這塊可以再細分下,給每一種功能單獨設計一個接口,可以是SQLAlg的子類,SQLAlg本身不要定義那么多接口,比較容易理解。
實現SQLDistinctExt
我參考SQLSendMessage
實現一個SQLDistinctExt
,只需要把load方法實現下就行了
override def load(spark: SparkSession, _path: String, params: Map[String, String]): Any = {
val inputTable = params.getOrElse("inputTable", _path)
val columns = params.getOrElse("columns", "")
val df = spark.table(inputTable)
if (columns.isEmpty) {
df.dropDuplicates().createOrReplaceTempView(inputTable)
} else {
df.dropDuplicates(columns.split(",")).createOrReplaceTempView(inputTable)
}
null
}
將這個類放到合適的地方能夠被mlsql找到
def findAlg(name: String) = {
mapping.get(name.capitalize) match {
case Some(clzz) =>
Class.forName(clzz).newInstance().asInstanceOf[SQLAlg]
case None =>
if (!name.contains(".") && (name.endsWith("InPlace") || name.endsWith("Ext"))) {
Class.forName(s"streaming.dsl.mmlib.algs.SQL${name}").newInstance().asInstanceOf[SQLAlg]
} else {
try {
Class.forName(name).newInstance().asInstanceOf[SQLAlg]
}
catch {
case e: Exception =>
throw new RuntimeException(s"${name} is not found")
}
}
}
}
還可以支持!這種宏,在CommandCollection
中添加:
使用方法
在流或者批任務里都可以使用哈,比如你經過處理得到一個table叫做t1,有a,b,c,d,e,f字段,根據a,b,c三個字段去重,你可以這樣寫
!distinct t1 "a,b,c"
你再select t1
會發現重復的已經去掉了,當然還可以設置watermarking