gitweixin
  • 首页
  • 小程序代码
    • 资讯读书
    • 工具类
    • O2O
    • 地图定位
    • 社交
    • 行业软件
    • 电商类
    • 互联网类
    • 企业类
    • UI控件
  • 大数据开发
    • Hadoop
    • Spark
    • Hbase
    • Elasticsearch
    • Kafka
    • Flink
    • 数据仓库
    • 数据挖掘
    • flume
    • Kafka
    • Hive
    • shardingsphere
    • solr
  • 开发博客
    • Android
    • php
    • python
    • 运维
    • 技术架构
    • 数据库
  • 程序员网赚
  • bug清单
  • 量化投资
  • 在线查询工具
    • 去行号
    • 在线时间戳转换工具
    • 免费图片批量修改尺寸在线工具
    • SVG转JPG在线工具

CDH重启cloudera-scm-agent报错:No socket could be created — ((‘127.0.0.1’, 9001): [Errno 98] Address already in use)

精品微信小程序开发门户,代码全部亲测可用

  • 首页   /  
  • 作者: east
  • ( 页面36 )
未分类 7月 27,2023

CDH重启cloudera-scm-agent报错:No socket could be created — ((‘127.0.0.1’, 9001): [Errno 98] Address already in use)

CDH集群重启 cloudera-scm-agent ,发现重启失败,查看日志如下:


[21/Jul/2023 19:49:10 +0000] 11006 HTTPServer Thread-2 _cplogging ERROR [21/Jul/2023:19:49:10] ENGINE Error in HTTP server: shutting down Traceback (most recent call last): File “/opt/cloudera/cm-agent/lib/python2.7/site-packages/cherrypy/process/servers.py”, line 225, in _start_http_thread self.httpserver.start() File “/opt/cloudera/cm-agent/lib/python2.7/site-packages/cheroot/server.py”, line 1326, in start raise socket.error(msg) error: No socket could be created — ((‘127.0.0.1’, 9001): [Errno 98] Address already in use)

错误表明 cloudera-scm-agent 在启动时无法创建HTTP服务器的套接字,原因是地址 127.0.0.1:9001 已经被占用了。这通常意味着另一个进程已经在监听相同的IP地址和端口号,导致 cloudera-scm-agent 无法绑定到该地址。

解决方案:

要解决这个问题,可以采取以下步骤:

  1. 查找占用端口的进程: 使用以下命令查找占用9001端口的进程:bash复制代码sudo netstat -tlnp | grep 9001 这将显示占用9001端口的进程的相关信息,包括进程ID (PID) 和进程名。
  2. 停止占用端口的进程: 如果上一步找到了占用9001端口的进程,可以尝试停止该进程,释放端口。使用以下命令杀死该进程(请注意替换 <PID> 为实际的进程ID):bash复制代码sudo kill <PID> 或者,如果是已知的服务进程,可以使用该服务的控制命令来停止服务。
  3. 修改端口号: 如果停止占用端口的进程不可行或不适合你的情况,可以考虑修改 cloudera-scm-agent 的配置,将其绑定到一个空闲的端口上。你可以编辑配置文件中的端口号,然后重新启动 cloudera-scm-agent。
  4. 确保正确配置: 确保 cloudera-scm-agent 的配置正确,并没有指定错误的端口号。
  5. 防火墙和安全组规则: 检查服务器的防火墙设置和网络安全组规则,确保端口号没有被阻止。
  6. 检查其他应用程序: 确保没有其他应用程序意外地使用了9001端口。
  7. 重新启动服务: 尝试重新启动 cloudera-scm-agent 服务。



作者 east
运维 7月 26,2023

linux提示 netstat: command not found要怎样安装

如果你在运行 netstat 命令时出现 “netstat: command not found” 的错误提示,这说明你的系统可能没有安装 netstat 工具。在一些最新的Linux发行版中,netstat 命令已经被弃用,取而代之的是其他工具,例如 ss (socket statistics)。

如果你使用的是较新的Linux发行版,可以尝试使用 ss 命令来代替 netstat,它提供了类似的功能。以下是使用 ss 命令来查看监听端口的方法:

bash复制代码sudo ss -tlnp | grep 9001

如果你仍然需要使用传统的 netstat 命令,你可以通过安装net-tools软件包来获得它。根据你的Linux发行版,可以使用以下命令来安装net-tools:

  • Ubuntu / Debian:
bash复制代码sudo apt-get update
sudo apt-get install net-tools
  • CentOS / RHEL:
bash复制代码sudo yum install net-tools
  • Fedora:
bash复制代码sudo dnf install net-tools

请注意,net-tools包含了很多网络工具,其中包括 netstat 命令。安装后,你应该能够正常使用 netstat 命令了。然而,如果你的Linux发行版已经不再支持 netstat 命令,建议使用 ss 命令来查看监听端口和网络连接的信息。

作者 east
bug清单 7月 26,2023

Datart页面报错:Handler dispatch failed; nested exception is java.lang.OutOfMemoryError: GC overhead limit exceeded

错误信息 “Handler dispatch failed; nested exception is java.lang.OutOfMemoryError: GC overhead limit exceeded” 表明datart应用程序在处理请求时发生了Java虚拟机(JVM)的内存溢出错误。具体来说,JVM无法及时回收垃圾对象,导致垃圾回收的开销超过了允许的阈值,从而触发了”GC overhead limit exceeded”错误。

可能的原因:

  1. 内存不足:datart应用程序所在的JVM分配的内存不足,导致垃圾回收无法正常进行,从而引发该错误。
  2. 内存泄漏:datart应用程序可能存在内存泄漏问题,导致大量对象无法被正确回收,最终耗尽了可用内存。
  3. 处理大数据量:datart应用程序在处理大规模数据或复杂查询时,可能导致内存占用过高,超过JVM限制。

解决方案:

针对上述可能的原因,可以采取以下步骤来解决问题:

  1. 增加JVM内存限制:增加datart应用程序所在JVM的内存限制,使其能够处理更大的数据量。这可以通过修改JVM启动参数中的-Xmx和-Xms选项来实现。例如,将-Xmx选项设置为较大的值,比如 “-Xmx4g” 表示最大可用内存为4GB。
  2. 检查内存泄漏:进行内存泄漏分析,查找可能导致内存泄漏的代码,并修复问题。可以使用一些Java内存分析工具(如VisualVM、MAT等)来辅助查找内存泄漏。
  3. 优化查询:对datart应用程序中的复杂查询进行优化,尽量减少内存占用。可以通过索引优化、查询优化等方式来改善查询性能。
  4. 分页查询:如果datart应用程序处理大数据量的查询,可以考虑引入分页查询,避免一次性加载过多数据到内存中。
  5. 升级应用程序:检查datart应用程序是否有已知的内存相关问题,并考虑升级到修复了这些问题的版本。
  6. 监控和警报:设置合适的监控和警报机制,当内存使用超过阈值时及时发出警报,以便及早发现和解决问题。
  7. 分析日志:查看datart应用程序的日志,特别是错误日志,以获取更多有关错误发生时的上下文信息,有助于进一步定位问题。
作者 east
bug清单, Hadoop 7月 25,2023

Transport-level exception trying to monitor health of NameNode at xxx: java.net.SocketTimeoutException: 45000 millis timeout while waiting for the channel to be ready for read

表明CDH 6.3.2中的某个组件(可能是其他节点的Datanode或NodeManager)在尝试监视位于CDH节点上的NameNode时,发生了Socket超时异常。这意味着在连接到NameNode时花费的时间超过了45秒,导致连接失败。

可能的原因:

  1. 网络问题:有可能是网络连接不稳定或者网络延迟导致连接超时。
  2. 资源不足:CDH的NameNode可能资源不足,导致响应变慢,从而引发超时异常。
  3. 防火墙或安全设置:防火墙或其他安全设置可能限制了节点之间的通信,导致连接超时。

解决方案:

针对上述可能的原因,可以采取以下步骤逐一排查和解决问题:

  1. 检查网络连接:确保所有节点之间的网络连接稳定,并且没有阻止节点之间通信的防火墙或其他网络限制。
  2. 检查资源:确认CDH上的NameNode是否具有足够的资源(CPU、内存、磁盘空间等)来处理请求。如果资源不足,可以考虑增加资源或优化配置。
  3. 检查防火墙和安全设置:确保防火墙或其他安全设置不会阻止节点之间的通信。可以检查防火墙规则和CDH安全配置。
  4. 检查NameNode日志:查看CDH上NameNode的日志,了解是否存在其他异常或错误信息,这可能有助于进一步定位问题。
  5. 调整超时时间:可以尝试增加超时时间,从而允许更长的连接时间。但这并不是根本解决问题的方法,只是一个临时调整。
  6. 更新或升级:如果发现该问题是由于已知的CDH或Hadoop bug引起的,可以尝试升级CDH版本或应用相关的补丁和更新。
  7. 联系支持:如果上述步骤无法解决问题,可以联系CDH或Hadoop的支持团队寻求进一步的帮助和调查。
作者 east
bug清单, Hadoop 7月 25,2023

CDH节点报“Role not started due to unhealthy host”,重启不了角色

CDH集群的 Datanode 挂掉了,要重新启动报错“Role not started due to unhealthy host”。查了一下,这表示主机处于不健康状态 。这个错误大概有下面的原因:

可能的原因:

  1. 主机故障:Datanode所在的主机可能存在硬件故障或者网络问题,导致主机处于不可用状态,从而Datanode无法正常启动。
  2. 资源不足:主机资源(例如CPU、内存、磁盘空间)不足,导致Datanode启动失败。
  3. 防火墙或安全设置:防火墙或其他安全设置可能会阻止Datanode与其他节点进行通信,导致启动失败。
  4. CDH组件问题:CDH组件可能出现问题,导致Datanode无法启动。

解决方案:

针对上述可能的原因,可以采取以下步骤逐一排查和解决问题:

  1. 检查主机状态:确保Datanode所在的主机处于健康状态,没有硬件故障或网络问题。可以通过运行系统命令或者在CDH管理界面查看主机状态。
  2. 检查资源:确认主机具有足够的资源(CPU、内存、磁盘空间等)来运行Datanode。如果资源不足,可以考虑升级主机或释放资源。
  3. 检查防火墙和安全设置:确保防火墙或其他安全设置不会阻止Datanode与其他节点进行通信。可以检查防火墙规则和CDH安全设置。
  4. 检查CDH组件状态:检查CDH的其他组件是否正常运行,特别是与Datanode相关的组件(如HDFS)。如果其他组件也出现问题,可能是由于CDH整体环境的故障。
  5. 查看日志:检查Datanode日志,通常在CDH的日志目录下,查看是否有相关错误信息提供更多线索。
  6. 重启服务:尝试重启Datanode服务,以便它重新连接到集群并解决任何临时问题。
  7. 联系支持:如果上述步骤无法解决问题,可以联系CDH或Hadoop支持团队寻求帮助。

后来还发现奇怪现象,jps查到datanode、namenode进程想要kill掉,一直kill不掉。经过排查,发现是服务器多块硬盘中其中一块坏了,导致CDH一直报
“Role not started due to unhealthy host ”。

作者 east
Flink 7月 23,2023

Flink SQL 秘密:掌握变更日志事件无序的艺术

简介

Alice 是一名数据工程师,负责公司的实时数据处理。她发现Flink SQL有时会产生更新(关于键)事件。但是,在 Flink 的早期版本中,这些事件无法直接写入 Kafka,因为 Kafka 本质上是一个仅追加的消息系统。幸运的是,Flink 社区在更高版本中发布了 Connectorupsert-kafka,支持写入更新事件。后来她发现Flink SQL作业readupsert-kafkaevents进行join操作时偶尔会出现错误。这让她对Flink SQL的可靠性产生了怀疑。她向社区报告了该问题,确认是变更日志事件乱序问题,随后在新版本中得到了解决。终于,她又可以继续愉快地使用 Flink SQL 了。从 Alice 使用 Flink SQL 的经历中我们可以了解到,实时数据处理并不总是顺利和直接的。为了让 Flink SQL 更容易理解,本文试图解开 Flink SQL 中变更日志事件乱序问题的谜团。我们首先介绍 Flink SQL 中的changelog,然后演示changelog事件乱序问题及其解决方案。最后,我们将针对这个问题提出最佳实践,以帮助您更好地理解和使用 Flink SQL 进行实时数据处理。

Flink SQL 中的 ChangelogChangelog 并不是 Flink SQL 发明的新概念。在关系数据库世界中,MySQL使用众所周知的binlog(二进制日志)来记录数据库中的所有修改操作,包括INSERT、UPDATE和DELETE操作。同样,Flink SQL 中的changelog 也用于记录这些数据变化,以实现增量数据处理。在 MySQL 中,binlog 可以用于数据的备份恢复、同步和复制。通过读取并解析binlog中的操作记录,可以实现增量数据的同步和复制。变更数据捕获(CDC)是一种常用的数据同步技术,它监视数据库中的数据变化并将这些变化转换​​为事件流进行实时处理。 CDC工具可用于将关系数据库中的数据变化实时传输到其他系统或数据仓库,以支持实时分析和报告。常见的CDC工具包括Debezium和Maxwell。通过 FLINK-15331 添加的 Flink CDC 支持,允许与外部系统的 CDC 数据实时集成,并通过 Flink 实现实时数据同步和分析。 在 Flink SQL 中生成和处理 Changelog 事件。虽然前面提到的 binlog 和 CDC 是与 Flink 集成的外部 Changelog 数据源,但 Flink SQL 内部也会生成 Changelog 数据。为了区分事件是否是更新事件,我们将仅包含 INSERT 类型事件的变更日志称为附加流,而另外包含其他类型(例如 UPDATE)事件的变更日志称为更新流。

Flink 中的一些操作(例如组聚合、去重)会产生更新事件。生成更新事件的运算符通常会维护状态,我们通常将它们称为有状态运算符。值得注意的是,并非所有有状态运算符都支持将更新流作为输入进行处理。例如,窗口聚合和间隔连接目前还不支持更新流作为输入。

熟悉Debezium数据格式(或数据库binlog解析)的用户可能想知道为什么Flink不使用复合UPDATE事件类型(就像数据库所做的那样),既包含UPDATE_BEFORE(UB)又包含UPDATE_AFTER(UA)并且更紧凑。事实上,我们在设计和实现 Flink 的回缩机制时就仔细评估了这个选项。复合 UPDATE 事件在某些场景下确实更加紧凑,可以解决特定问题(例如 FLINK-9528),但我们选择不使用它的原因主要是以下两个方面:拆分事件无论事件类型如何,其事件结构都是相同的(仅 RowKind 不同),这使得序列化更简单。如果使用复合 UPDATE 事件,则事件要么是异构的,要么 INSERT/DELETE 也被建模为 UPDATE 事件(例如,INSERT 事件仅具有 UA,DELETE 事件仅具有 UB)。在分布式环境中,经常涉及数据混洗操作(例如,联接、聚合)。即使使用复合 UPDATE 事件,在某些场景中进行混洗时,它们仍然必须拆分为单独的 DELETE 和 INSERT 事件。

作者 east
doris 7月 18,2023

java代码判断doris的某一天的分区是否存在

需要使用doris的SHOW PARTITIONS命令来查看表的分区信息。这个命令会显示表的所有分区信息,包括分区名、范围、副本数等。您可以根据您设定的动态分区规则判断是否有缺失或多余的分区1。

要通过java代码执行doris的SHOW PARTITIONS命令,您可以使用以下步骤:

  • 导入doris的jdbc驱动包,例如doris-jdbc-0.15.0.jar2。
  • 创建一个数据库连接对象,指定doris的url、用户名和密码。
  • 创建一个语句对象,执行SHOW PARTITIONS FROM tbl1命令,其中tbl1是您要查询的表名。
  • 获取一个结果集对象,遍历结果集,判断某一天的分区是否存在。

以下是一个可能的java代码示例,仅供参考:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class DorisPartitionTest {

    public static void main(String[] args) throws Exception {
        // Load the driver
        Class.forName("org.apache.doris.jdbc.Driver");
        // Create a connection object
        Connection conn = DriverManager.getConnection("jdbc:doris://127.0.0.1:9030?database=test_db", "root", "");
        // Create a statement object
        Statement stmt = conn.createStatement();
        // Execute the command
        ResultSet rs = stmt.executeQuery("SHOW PARTITIONS FROM tbl1");
        // Define a variable to store the partition name of the day to be queried
        String partitionName = "p20210717";
        // Define a variable to store the result of whether the partition exists
        boolean partitionExists = false;
        // Traverse the result set
        while (rs.next()) {
            // Get the partition name column
            String name = rs.getString("PartitionName");
            // Compare with the partition name to be queried
            if (name.equals(partitionName)) {
                // If equal, set the result to true and break the loop
                partitionExists = true;
                break;
            }
        }
        // Close the resources
        rs.close();
        stmt.close();
        conn.close();
        // Print the result
        System.out.println("The partition " + partitionName + " exists: " + partitionExists);
    }
}
作者 east
Spark 7月 17,2023

spark dataframe如何提取某一行的字段的值

有几种方法可以从Spark dataframe中提取某一行的字段的值,使用scala语言实现。我会给你一些例子和链接,你可以参考一下。

  • 一种方法是使用**row.getString(index)**方法,其中index是字段在行中的位置。例如,如果你想要获取第一行的第一个字段的值,你可以这样写:
val row = df.first() // 获取第一行
val value = row.getString(0) // 获取第一个字段的值

这个方法需要你知道字段的索引和类型。1

  • 另一种方法是使用**row.getAsT**方法,其中T是字段的类型,columnName是字段的名称。例如,如果你想要获取第一行的name字段的值,你可以这样写:
val row = df.first() // 获取第一行
val value = row.getAs[String]("name") // 获取name字段的值

这个方法不需要你知道字段的索引,但需要你知道字段的类型和名称。2

  • 还有一种方法是使用**df.select(columnName).collect()**方法,其中columnName是字段的名称。这个方法会返回一个包含所有行的字段值的数组。例如,如果你想要获取所有行的name字段的值,你可以这样写:
val values = df.select("name").collect() // 获取所有行的name字段的值

复制

这个方法不需要你知道字段的索引和类型,但需要你知道字段的名称。

作者 east
Spark 6月 19,2023

spark dataframe left join另一个dataframe 空值异常的问题

当在Spark开发时,某个字段有空值会出现不少意想不到的情况。Spark SQL中对两个Dataframe使用join时,当作为连接的字段的值含有null值。由于null表示的含义是未知,既不知道有没有,在SQL中null值与任何其他值的比较(即使是null)永远不会为真。故在进行连接操作时null == null不为True,所以结果中不会出现该条记录,即左侧表格的这条记录对应右侧的值均为null。

解决方法一:

如果两个DataFrame进行left join时,多个字段的值有空值,那么结果就会为空。为了解决这个问题,我们可以先对这两个DataFrame进行处理,在处理的过程中将空值替换成一个特殊值,例如:

import org.apache.spark.sql.functions._
import org.apache.spark.sql.{Column, DataFrame}

// 左边的DataFrame为leftDF,右边的DataFrame为rightDF
// 给定leftDF和rightDF共同进行left join的字段列
val joinColumns: Seq[String] = Seq("col1", "col2", "col3")

// 定义替换的特殊值
val specialValue: String = "__NULL__"

// 对leftDF和rightDF的joinColumns列进行空值替换
val leftJoinDF: DataFrame = replaceNullsWithSpecialValue(leftDF, joinColumns, specialValue)
val rightJoinDF: DataFrame = replaceNullsWithSpecialValue(rightDF, joinColumns, specialValue)

// 对leftJoinDF和rightJoinDF进行join操作
val joinedDF: DataFrame = leftJoinDF.join(rightJoinDF, joinColumns, "left")

// 定义空值替换函数
def replaceNullsWithSpecialValue(df: DataFrame, columns: Seq[String], replacement: String): DataFrame = {
  val columnsToReplace: Seq[Column] = columns.map(col(_))
  val columnsToKeep = df.columns.filterNot(columns.contains(_)).map(col)
  df.select((columnsToReplace ++ columnsToKeep):_*).na.fill(replacement, columnsToReplace)
}

在这里,我们使用na.fill()函数将DataFrame中的空值替换为特殊值。在处理完之后,我们就可以对两个DataFrame进行left join操作了。

解决方法二:

一种可能的解决方案是使用NULL safe equality operator(<=>),它可以在join条件中处理NULL值,使得NULL值与NULL值相等。例如,如果你有两个dataframe,df1和df2,你想要根据多个字段进行left join,你可以写成:

import org.apache.spark.sql.functions._
val joinedDF = df1.join(df2, df1("col1") <=> df2("col1") && df1("col2") <=> df2("col2"), "left")

这样,即使col1或col2中有NULL值,也不会影响join的结果。


关注公众号“大模型全栈程序员”回复“大数据面试”获取800页左右大数据面试宝典 ,回复“大数据”获取多本大数据电子书


作者 east
doris, Spark 6月 16,2023

Spark写数据到Doris报错node and exceeded the max retry times

用spark dataframe向doris写数据时,报下面错误:

Failed to load data on BE: http://192.168.50.10:18040/api/mydb/dwd_virtual_table/_stream_load? node and exceeded the max retry times.

发现表没写入成功。刚开始很困惑,后来发现是 dataFrame中的字段和目标表不一致 。

这种提示很不友好,有没有更好方式提示,方法是有的,可以用jdbc写入,发现错误时可以看到具体的提示。代码参考如下:

def writeByJDBC(dataframe: DataFrame, dorisTable: String): Unit = {
    dataframe.write.format("jdbc")
      .mode(SaveMode.Append)
      .option("driver", "com.mysql.jdbc.Driver")
      .option("url", "jdbc:mysql://" + DORIS_HOST + ":9030/" +DATABASE_NAME + "?rewriteBatchedStatements=false")
      .option("batchsize", "" + WRITE_BATCH_SIZE)
      .option("user", DORIS_USER)
      .option("password", DORIS_PASSWORD)
      .option("isolationLevel", "NONE")
      //  .option("doris.write.fields","case_id,defendant_name,finance_name,mediation_name,mediator_name,dt")
      .option("dbtable", dorisTable)
      .save()
  }

不过这种方式还是没有Spark Doris Connector的方式写效率高,可以用上面jdbc方式调试,没问题再切换 Spark Doris Connector 方式:

def writeByDoris(dataframe: DataFrame, dorisTable: String): Unit = {
dataframe.write.format(“doris”)
.option(“doris.table.identifier”, dorisTable)
.option(“doris.fenodes”, DORIS_HOST + “:” + DORIS_FE_HTTP_PORT)
.option(“user”, DORIS_USER)
.option(“password”, DORIS_PASSWORD)
.option(“sink.batch.size”, WRITE_BATCH_SIZE)
.option(“sink.max-retries”, 3)
.option(“doris.request.retries”, 6)
.option(“doris.request.retries”, 100)
.option(“doris.request.connect.timeout.ms”, 60000)
.save()
}

关注公众号“大模型全栈程序员”回复“大数据面试”获取800页左右大数据面试宝典 ,回复“大数据”获取多本大数据电子书

作者 east
Spark 6月 16,2023

spark sql多个指标合并为1条sql

在 Spark SQL 指标开发中,使用一条 SQL 语句来计算多个指标是常见的做法。以下是几种常用的方法:

  1. 使用子查询:将多个指标的计算逻辑放在子查询中,再在外层 SELECT 语句中进行聚合。这种方式可以避免代码冗余,但可能会降低 SQL 语句的可读性。
  2. 使用 Window 函数:使用 Window 函数可以在一条 SQL 语句中计算多个指标,并且可以避免对同一个数据集进行多次扫描。具体操作是使用 over() 函数配合 sum、avg、max、min等聚合函数。这种方式相比子查询可以提升 SQL 的效率,但需要熟练掌握 Window 函数的使用方法。
  3. 使用 UDAF:如果需要计算的指标比较复杂,可以考虑开发自定义聚合函数(UDAF),这样可以将计算逻辑封装到统一的函数中,提高代码的可复用性和可维护性。

例子:

  1. 使用子查询进行多指标计算

假设我们有一个订单表 orders,包含以下字段:order_id, customer_id, order_date, amount。我们需要计算每个客户在 2022 年的订单数量和总订单金额。可以使用如下 SQL 语句实现:

SELECT 
  customer_id, 
  (SELECT COUNT(*) 
   FROM orders 
   WHERE customer_id = o.customer_id AND YEAR(order_date) = 2022) AS order_count, 
  (SELECT SUM(amount) 
   FROM orders 
   WHERE customer_id = o.customer_id AND YEAR(order_date) = 2022) AS total_amount 
FROM orders o 
GROUP BY customer_id;

这个 SQL 语句使用了两个子查询来计算每个客户在 2022 年的订单数量和总订单金额。子查询返回的结果会作为 select 语句中的一个列,因此可以使用 group by 对客户进行分组。

  1. 使用 Window 函数进行多指标计算

使用 Window 函数可以更方便地对查询结果进行分析。假设我们有一个销售表 sales,包含以下字段:sale_id, customer_id, product_id, sale_date, sale_amount。我们需要计算以下指标:每个客户的总销售额、每个客户的最大销售额、每个客户的销售额排名。可以使用如下 SQL 语句实现:

SELECT 
  customer_id, 
  SUM(sale_amount) OVER (PARTITION BY customer_id) AS total_sale, 
  MAX(sale_amount) OVER (PARTITION BY customer_id) AS max_sale, 
  RANK() OVER (PARTITION BY customer_id ORDER BY sale_amount DESC) AS sale_rank 
FROM sales;

这个 SQL 语句使用了三个 Window 函数,分别计算每个客户的总销售额、最大销售额和销售额排名。这里我们将结果按客户分组,然后使用了 Partition By 子句指定了客户维度。

  1. 使用自定义聚合函数进行多指标计算

自定义聚合函数(UDAF)可以针对特定的需求编写自己的聚合逻辑。以计算最小值、最大值和平均值为例,我们可以实现一个自定义平均值 UDAF:

import org.apache.spark.sql.expressions.MutableAggregationBuffer
import org.apache.spark.sql.expressions.UserDefinedAggregateFunction
import org.apache.spark.sql.Row
import org.apache.spark.sql.types._
 
class CustomAvg extends UserDefinedAggregateFunction {
 
  // 输入参数的数据类型
  def inputSchema: StructType = new StructType().add("inputColumn", DoubleType)
 
  // 中间结果的数据类型
  def bufferSchema: StructType = new StructType().add("sum", DoubleType).add("count", LongType)
 
  // 输出结果的数据类型
  def dataType: DataType = DoubleType
 
  // 是否固定输入参数类型
  def deterministic: Boolean = true
 
  // 初始化中间结果缓存
  def initialize(buffer: MutableAggregationBuffer): Unit = {
    buffer(0) = 0.0 // sum
    buffer(1) = 0L // count
  }
 
  // 更新中间结果缓存
  def update(buffer: MutableAggregationBuffer, input: Row): Unit = {
    if (!input.isNullAt(0)) {
      buffer(0) = buffer.getDouble(0) + input.getDouble(0)
      buffer(1) = buffer.getLong(1) + 1
    }
  }
 
  // 合并中间结果缓存
  def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit = {
    buffer1(0) = buffer1.getDouble(0) + buffer2.getDouble(0)
    buffer1(1) = buffer1.getLong(1) + buffer2.getLong(1)
  }
 
  // 计算最终结果
  def evaluate(buffer: Row): Any = {
    buffer.getDouble(0) / buffer.getLong(1)
  }
}

这里我们实现了一个 CustomAvg UDAF,可以通过输入若干个 Double 类型的值,计算它们的平均值并返回。我们可以在 SparkSQL 中使用这个 UDAF 计算多个指标的平均值:

SELECT 
  CustomAvg(column1) AS avg1, 
  CustomAvg(column2) AS avg2, 
  CustomAvg(column3) AS avg3 
FROM table;

这个 SQL 语句使用了 CustomAvg UDAF 计算了三个列的平均值,可以根据实际需求进行扩展。

关注公众号“大模型全栈程序员”回复“大数据面试”获取800页左右大数据面试宝典 ,回复“大数据”获取多本大数据电子书

作者 east
doris 6月 13,2023

Spark 写入数据到doris异常

用spark写入到doris,由于服务器配置不高, sink.batch.size 设置过大时,超出服务器内存限制,doris be端直接闪崩。如果 sink.batch.size 设置过小,则出现写入次数太频繁无法写入。 调整 write 的
sink.batch.size 参数大小,逐步增加 batchsize 大小,以达到更好的写入性能与内存占用的平衡。例如,可以逐渐将 batchsize 参数的值从 200 调整到 500,1000,2000,以找到最好的性能与内存占用平衡点。 刚开始设置10000时服务器be端闪崩,后来设置200时又写到中途报错,最后找到2000这个平衡点。

def writeDoris(dataframe: DataFrame, dorisTable: String): Unit = {
dataframe.write.format(“doris”)
.option(“doris.table.identifier”, dorisTable)
.option(“doris.fenodes”, DORIS_HOST + “:” + DORIS_FE_HTTP_PORT)
.option(“user”, DORIS_USER)
.option(“password”, DORIS_PASSWORD)
.option(“sink.batch.size”, 2000)
.save()
}

关注公众号“大模型全栈程序员”回复“大数据面试”获取800页左右大数据面试宝典 ,回复“大数据”获取多本大数据电子书

作者 east

上一 1 … 35 36 37 … 93 下一个

关注公众号“大模型全栈程序员”回复“小程序”获取1000个小程序打包源码。回复”chatgpt”获取免注册可用chatgpt。回复“大数据”获取多本大数据电子书

标签

AIGC AI创作 bert chatgpt github GPT-3 gpt3 GTP-3 hive mysql O2O tensorflow UI控件 不含后台 交流 共享经济 出行 图像 地图定位 外卖 多媒体 娱乐 小程序 布局 带后台完整项目 开源项目 搜索 支付 效率 教育 日历 机器学习 深度学习 物流 用户系统 电商 画图 画布(canvas) 社交 签到 联网 读书 资讯 阅读 预订

官方QQ群

小程序开发群:74052405

大数据开发群: 952493060

近期文章

  • spark内存溢出怎样区分是软件还是代码原因
  • MQTT完全解析和实践
  • 解决运行Selenium报错:self.driver = webdriver.Chrome(service=service) TypeError: __init__() got an unexpected keyword argument ‘service’
  • python 3.6使用mysql-connector-python报错:SyntaxError: future feature annotations is not defined
  • 详解Python当中的pip常用命令
  • AUTOSAR如何在多个供应商交付的配置中避免ARXML不兼容?
  • C++thread pool(线程池)设计应关注哪些扩展性问题?
  • 各类MCAL(Microcontroller Abstraction Layer)如何与AUTOSAR工具链解耦?
  • 如何设计AUTOSAR中的“域控制器”以支持未来扩展?
  • C++ 中避免悬挂引用的企业策略有哪些?

文章归档

  • 2025年7月
  • 2025年6月
  • 2025年5月
  • 2025年4月
  • 2025年3月
  • 2025年2月
  • 2025年1月
  • 2024年12月
  • 2024年11月
  • 2024年10月
  • 2024年9月
  • 2024年8月
  • 2024年7月
  • 2024年6月
  • 2024年5月
  • 2024年4月
  • 2024年3月
  • 2023年11月
  • 2023年10月
  • 2023年9月
  • 2023年8月
  • 2023年7月
  • 2023年6月
  • 2023年5月
  • 2023年4月
  • 2023年3月
  • 2023年1月
  • 2022年11月
  • 2022年10月
  • 2022年9月
  • 2022年8月
  • 2022年7月
  • 2022年6月
  • 2022年5月
  • 2022年4月
  • 2022年3月
  • 2022年2月
  • 2022年1月
  • 2021年12月
  • 2021年11月
  • 2021年9月
  • 2021年8月
  • 2021年7月
  • 2021年6月
  • 2021年5月
  • 2021年4月
  • 2021年3月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2020年7月
  • 2020年6月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年2月
  • 2020年1月
  • 2019年7月
  • 2019年6月
  • 2019年5月
  • 2019年4月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年12月
  • 2018年7月
  • 2018年6月

分类目录

  • Android (73)
  • bug清单 (79)
  • C++ (34)
  • Fuchsia (15)
  • php (4)
  • python (45)
  • sklearn (1)
  • 云计算 (20)
  • 人工智能 (61)
    • chatgpt (21)
      • 提示词 (6)
    • Keras (1)
    • Tensorflow (3)
    • 大模型 (1)
    • 智能体 (4)
    • 深度学习 (14)
  • 储能 (44)
  • 前端 (4)
  • 大数据开发 (491)
    • CDH (6)
    • datax (4)
    • doris (31)
    • Elasticsearch (15)
    • Flink (78)
    • flume (7)
    • Hadoop (19)
    • Hbase (23)
    • Hive (41)
    • Impala (2)
    • Java (71)
    • Kafka (10)
    • neo4j (5)
    • shardingsphere (6)
    • solr (5)
    • Spark (100)
    • spring (11)
    • 数据仓库 (9)
    • 数据挖掘 (7)
    • 海豚调度器 (10)
    • 运维 (34)
      • Docker (3)
  • 小游戏代码 (1)
  • 小程序代码 (139)
    • O2O (16)
    • UI控件 (5)
    • 互联网类 (23)
    • 企业类 (6)
    • 地图定位 (9)
    • 多媒体 (6)
    • 工具类 (25)
    • 电商类 (22)
    • 社交 (7)
    • 行业软件 (7)
    • 资讯读书 (11)
  • 嵌入式 (71)
    • autosar (63)
    • RTOS (1)
    • 总线 (1)
  • 开发博客 (16)
    • Harmony (9)
  • 技术架构 (6)
  • 数据库 (32)
    • mongodb (1)
    • mysql (13)
    • pgsql (2)
    • redis (1)
    • tdengine (4)
  • 未分类 (7)
  • 程序员网赚 (20)
    • 广告联盟 (3)
    • 私域流量 (5)
    • 自媒体 (5)
  • 量化投资 (4)
  • 面试 (14)

功能

  • 登录
  • 文章RSS
  • 评论RSS
  • WordPress.org

All Rights Reserved by Gitweixin.本站收集网友上传代码, 如有侵犯版权,请发邮件联系yiyuyos@gmail.com删除.