deequ data-column profile 代码分析
admin
2024-02-04 04:27:01
0

data-column profile 的String 类型侦测

deequ的profile 带来了一个 string 类型的字段类型侦测,以deequ的例子来说明这个特性,数据定义为:
case class RawData(productName: String, totalNumber: String, status: String, valuable: String)

但输出的结果如下
Column ‘productName’:
completeness: 1.0
approximate number of distinct values: 5
datatype: String

Column ‘totalNumber’:
completeness: 1.0
approximate number of distinct values: 6
datatype: Fractional

这个侦测是通过class StatefulDataType 来实现的。

object ColumnProfiler 核心代码

核心执行代码在object ColumnProfiler的profile 函数中,具体如下:

/*** Profile a (potentially very large) dataset.** @param data                             data dataset as dataframe* @param restrictToColumns                an contain a subset of columns to profile, otherwise*                                         all columns will be considered ,限制列,默认所有列* @param printStatusUpdates              是否打印进度* @param lowCardinalityHistogramThreshold the maximum (estimated) number of distinct values*                                         in a column until which we should compute exact*                                         histograms for it (defaults to 120)*                                         是否计算直方图的阀值,对值数量小于阀值的计算直方图* @param metricsRepository                the repo to store metrics 保存的repository* @param reuseExistingResultsUsingKey     key for reuse existing result  使用已有的结果,即Repository里面的数据* @param failIfResultsForReusingMissing   true if we have results for reusing* @param saveInMetricsRepositoryUsingKey  key for saving in metrics repo   保存KEY* @param kllProfiling                     是否自定义了KLL 参数,kll 可以参考https://www.51cto.com/article/711445.html* @param kllParameters                    parameters for KLL Sketches ,注意是否使用kll与此参数无关,具体参考doAnalysisRun* @param predefinedTypes                  预先定义的column Type,如果string column 有定义Type,将不进行detect, 具体见getAnalyzersForGenericStats 函数* @return the profile of columns*/// scalastyle:off argcountprivate[deequ] def profile(data: DataFrame,restrictToColumns: Option[Seq[String]] = None,printStatusUpdates: Boolean = false,lowCardinalityHistogramThreshold: Int =ColumnProfiler.DEFAULT_CARDINALITY_THRESHOLD,metricsRepository: Option[MetricsRepository] = None,reuseExistingResultsUsingKey: Option[ResultKey] = None,failIfResultsForReusingMissing: Boolean = false,saveInMetricsRepositoryUsingKey: Option[ResultKey] = None,kllProfiling: Boolean = false,kllParameters: Option[KLLParameters] = None,predefinedTypes: Map[String, DataTypeInstances.Value] = Map.empty): ColumnProfiles = {// Ensure that all desired columns existrestrictToColumns.foreach { restrictToColumns =>restrictToColumns.foreach { columnName =>require(data.schema.fieldNames.contains(columnName), s"Unable to find column $columnName")}}// Find columns we want to profileval relevantColumns = getRelevantColumns(data.schema, restrictToColumns)// First passif (printStatusUpdates) {println("### PROFILING: Computing generic column statistics in pass (1/3)...")}// We compute completeness, approximate number of distinct values// and type detection for string columns in the first passval analyzersForGenericStats = getAnalyzersForGenericStats(data.schema,relevantColumns,predefinedTypes)//使用AnalysisRunner 运行,但不是用addcheck,改用addAnalyzers,check 最后也是转为Analyzer// check 转analyzers  代码在 private[deequ] def doVerificationRun( 中的如下代码//  val analyzers = requiredAnalyzers ++ checks.flatMap { _.requiredAnalyzers() }// val analysisResults = AnalysisRunner.doAnalysisRun(//  data,//   analyzers.distinct,////var analysisRunnerFirstPass = AnalysisRunner.onData(data).addAnalyzers(analyzersForGenericStats).addAnalyzer(Size())analysisRunnerFirstPass = setMetricsRepositoryConfigurationIfNecessary(analysisRunnerFirstPass,metricsRepository,reuseExistingResultsUsingKey,failIfResultsForReusingMissing,saveInMetricsRepositoryUsingKey)//使用AnalysisRunner 运行,和constraint 相同val firstPassResults = analysisRunnerFirstPass.run()val genericStatistics = extractGenericStatistics(relevantColumns,data.schema,firstPassResults,predefinedTypes)// Second passif (printStatusUpdates) {println("### PROFILING: Computing numeric column statistics in pass (2/3)...")}// We cast all string columns that were detected as numericval castedDataForSecondPass = castNumericStringColumns(relevantColumns, data,genericStatistics)// We compute mean, stddev, min, max for all numeric columnsval analyzersForSecondPass = getAnalyzersForSecondPass(relevantColumns,genericStatistics, kllProfiling, kllParameters)var analysisRunnerSecondPass = AnalysisRunner.onData(castedDataForSecondPass).addAnalyzers(analyzersForSecondPass)analysisRunnerSecondPass = setMetricsRepositoryConfigurationIfNecessary(analysisRunnerSecondPass,metricsRepository,reuseExistingResultsUsingKey,failIfResultsForReusingMissing,saveInMetricsRepositoryUsingKey)//使用AnalysisRunner 运行,和constraint 相同val secondPassResults = analysisRunnerSecondPass.run()val numericStatistics = extractNumericStatistics(secondPassResults)// Third passif (printStatusUpdates) {println("### PROFILING: Computing histograms of low-cardinality columns in pass (3/3)...")}// We compute exact histograms for all low-cardinality string columns, find those hereval targetColumnsForHistograms = findTargetColumnsForHistograms(data.schema, genericStatistics,lowCardinalityHistogramThreshold)// Find out, if we have values for those we can reuseval analyzerContextExistingValues = getAnalyzerContextWithHistogramResultsForReusingIfNecessary(metricsRepository,reuseExistingResultsUsingKey,targetColumnsForHistograms)// The columns we need to calculate the histograms forval nonExistingHistogramColumns = targetColumnsForHistograms.filter { column => analyzerContextExistingValues.metricMap.get(Histogram(column)).isEmpty }// Calculate and save/append results if necessaryval histograms: Map[String, Distribution] = getHistogramsForThirdPass(data,nonExistingHistogramColumns,analyzerContextExistingValues,printStatusUpdates,failIfResultsForReusingMissing,metricsRepository,saveInMetricsRepositoryUsingKey)val thirdPassResults = CategoricalColumnStatistics(histograms)createProfiles(relevantColumns, genericStatistics, numericStatistics, thirdPassResults)}

限制分析范围及避免String Column Detection

参考以下代码可以指定,通过输入column name Seq 可以指定分析column范围。

/*** Can be used to specify a subset of columns to look at* 限制3分析的colum 列表* @param restrictToColumns The columns to look at*/
def restrictToColumns(restrictToColumns: Seq[String]): this.type = {this.restrictToColumns = Option(restrictToColumns)this
}

前面也提到了predefinedTypes可以避免String Column Detection,以下是实现逻辑。

//通过DataType 函数进行String 类型的detection
private[this] def getAnalyzersForGenericStats(schema: StructType,relevantColumns: Seq[String],predefinedTypes: Map[String, DataTypeInstances.Value]): Seq[Analyzer[_, Metric[_]]] = {schema.fields.filter { field => relevantColumns.contains(field.name) }.flatMap { field =>val name = field.nameif (field.dataType == StringType && !predefinedTypes.contains(name)) {Seq(Completeness(name), ApproxCountDistinct(name), DataType(name))} else {Seq(Completeness(name), ApproxCountDistinct(name))}}
}

相关内容

热门资讯

魅力南疆12天11晚小团游:邂... 魅力南疆12天11晚小团游:邂逅巴楚红海景区的独特风光 新疆旅游咨询: 小敏18509915393 ...
AI数字人、VR大空间、MR任... 在山西博物院,虚拟星推官“青鸟”身着晋绣华服,向游客讲述三晋文明;在伊犁将军府,数字人“将军”耐心解...
文水:景中有“警”讲安全 筑牢... 随着学生暑假来临,景区旅游高峰期也来临,为持续做好旅游季道路交通安全管理工作,确保辖区景区交通安全持...
希腊网红游名城:最喜欢成都,天... “这边的环境太好了!”“这里是野餐聚会的绝佳场所,非常浪漫。”7月5日,玛丽安(Mariana)和索...
漫长的季节想表达什么 漫长的季节想表达什么漫长的季节想表达什么:漫长的季节讲的是关于时间的流逝和内心的变化。它催促我们从未...
亲子游带动暑期市场结构性升级 亲子游驱动暑期旅游市场结构性升级:IP赋能、服务创新与消费分层成新趋势 2025年暑期旅游市场迎来...
龙飞凤舞的意思是什么? 龙飞凤舞的意思是什么? 龙飞凤舞原形容山势蜿蜒起伏,气势磅礴。现多指书法笔势有力,灵活奔放。出处:宋...
真正经历过的饥荒有多可怕 真正经历过的饥荒有多可怕如果从历史来看,世界上不管什么制度的国家,没经历过饥荒的国家估计少之又少
快收藏!暑假南阳各景区活动来了... 暑期将至那颗渴望逃离日常、奔赴山川湖海的心是不是已经开始蠢蠢欲动啦这个夏天南阳景区为大家准备了超多惊...
伊犁印象:9天8晚的心灵牧歌,... 伊犁印象:9天8晚的心灵牧歌,在那拉提空中草原的自由放飞 新疆旅游咨询: 小敏1850991539...
外婆桥洛天依葫芦丝曲谱 外婆桥洛天依葫芦丝曲谱 不好找,这个不知是不是你要的:
新疆8天7晚美食之旅:舌尖上的... 新疆8天7晚美食之旅:舌尖上的西域奇遇 新疆旅游咨询: 小敏18509915393 小钰176908...
原创 2... 作者︱余在洋 五粮液计划在今年下半年推出29度五粮液,这一消息很快就在业内引起发了媒体关注。 在渠道...
急~~~求解,李克勤《终身美丽... 急~~~求解,李克勤《终身美丽》这首歌到底说的是什么意思?求解,李克勤《终身美丽》这首歌到底说的是什...
传承中的色香味,薄筋光——陕西... 陕西臊子面,作为西北地区最具特色的传统面食之一,承载着深厚的历史文化底蕴,其独特的制作工艺和色香味俱...
江苏蒸菜,蒸出家的味道,蒸出爱... 江苏蒸菜,以“鲜嫩清香、原汁原味”著称,是江南饮食文化中一抹温润的底色。它不靠浓油赤酱夺味,仅凭水汽...
原创 三... “民以食为天,食以安为先”!一到三伏天,大家都觉得吃西瓜解暑又爽口,可您知道吗,西瓜吃多了未必全是好...
瞭望评 | 何来“整治吃喝”之... 整治违规吃喝,确实动了少数人的奶酪。 这个奶酪,并非是一顿饕餮大餐,而是维系各种小圈子的吃喝局。 曾...
我应该感到自豪才对是一篇什么文... 我应该感到自豪才对是一篇什么文章《我应该感到自豪才对》,这是一篇童话,讲述了小红马嘲笑小骆驼难看,而...