Apache Doris使用Stream Load方式insert数据

Stream Load是一种通过HTTP协议进行PUT操作,将数据导入到Doris。数据导入是同步操作,导入完成会返回成功或失败的response。一些具体的使用说明可以通过help stream load获取

1. 数据导入流程

  • 方式一,优点是每次的Coordinator可能是不同的BE,减低了压力:
    1. client向FE请求,FE找出一个BE作为Coordinator
    2. client向Coordinator发送数据,Coordinator对数据进行分发,发送到各个BE
    3. Coordinator向client返回发送的结果
  • 方式二:
    1. client直接向一个BE1发送数据,BE1对数据进行分发,发送到各个BE
    2. BE1向client返回发送的结果

2. 使用python实现Stream load

import requests
from requests.auth import HTTPBasicAuth
import uuid
import json

if __name__ == '__main__':

    url = 'http://192.168.8.112:7030/api/dataQualitySystem/test/_stream_load'
    json_data = {"records": [{"id": 3, "name": "zhangsan"}, {"id": 4, "name": "lisi"}]}
    doris_headers = {
        'label': str(uuid.uuid1()),
        'format': 'json',
        'expect': '100 continue',
        'strip_outer_array': "true",
        'json_root': '$.records',
        'where': 'id=3'
    }
    auth = HTTPBasicAuth('root', 'Root_123')

    response = requests.put(url=url,
                            json=json_data,
                            headers = doris_headers,
                            auth = auth
                            )

    redict_url = response.url
    redict_headers = {
        'label': str(uuid.uuid1()),
        'format': 'json',
        'strip_outer_array': "true",
        'json_root': '$.records',
        'where': 'id=3'

    }
    redict_response = requests.put(url=redict_url,
                                   json=json_data,
                                   headers = redict_headers,
                                   auth = auth
                                   )
    if json.loads(redict_response.text).get("Status") != "Success":
        ex = Exception(redict_response.text)
        raise ex

    print(redict_response.text)

程序说明如下:

  • url变量部分:
    1. 7030端口是fe.conf中的http_port
    2. dataQualitySystem/test分别指数据库和表
  • doris_headers字典部分:
    1. 可以自己指定,也可以由doris系统生成,但label需保证在一个database唯一。除了stream load,也不能和其它数据导入方式的label相同
    2. expect: 100 continue表示client先向server发送消息说,我的数据超过了1024字节,server端回应说会接收数据的,之后client再向server端发送数据
    3. strip_outer_array表示导入多条数据,json_root表示多条数据的list对应的key
    4. where表示对导入的数据进行条件过滤
  • 因为FE重定向到作为Coordinator的BE,python的requests虽然可以自动实现重定向到Coordinator,但是不能携带账号和密码进行认证,会报异常:no valid Basic authorization,所以自己手动实现重定向到BE(该BE相当于Coordinator)

执行结果如下:

{
    "TxnId": 201601,
    "Label": "c217d2f4-3dc5-11ec-862d-5cbaef5fa158",
    "Status": "Success",
    "Message": "OK",
    "NumberTotalRows": 2,
    "NumberLoadedRows": 1,
    "NumberFilteredRows": 0,
    "NumberUnselectedRows": 1,
    "LoadBytes": 71,
    "LoadTimeMs": 28,
    "BeginTxnTimeMs": 0,
    "StreamLoadPutTimeMs": 4,
    "ReadDataTimeMs": 0,
    "WriteDataTimeMs": 10,
    "CommitAndPublishTimeMs": 13
}

返回结果说明:

  • Status: 如果是Publish Timeout,表示导入成功,只是数据暂时对用户不可见
  • ExistingJobStatus:如果Label重复,已经存在的Lable的Status
  • NumberTotalRows:导入的总数据条数,等于NumberLoadedRows + NumberFilteredRows + NumberUnselectedRows
  • NumberLoadedRows:导入成功的数据条数
  • NumberFilteredRows:导入失败的数据条数
  • NumberUnselectedRows:被where条件过滤的数据条数
  • LoadTimeMs:导入完成时间。单位毫秒
  • BeginTxnTimeMs:向Fe或BE请求,开始一个事务所花费的时间
  • StreamLoadPutTimeMs:向Fe或BE请求,获取导入数据执行计划所花费的时间
  • ReadDataTimeMs:读取数据所花费的时间
  • WriteDataTimeMs:写入数据操作所花费的时间
  • CommitAndPublishTimeMs:向Fe或BE请求,提交并且发布事务所花费的时间

3. Doris HTTP headers参数说明

  • max_filter_ratio
    导入数据的容错率,默认为0,范围为0-1,计算方式为:NumberFilteredRows / (NumberLoadedRows + NumberFilteredRows)
  • exec_mem_limit:导入的内存限制。默认为 2GB,单位为字节

4. 导入资源设置

  • stream_load_default_timeout_second:FE配置,默认300秒,单位为秒,超过该时间的导入任务将被取消变成CANCELLED。可以通过Doris HTTP headers设置或fe.conf进行设置
  • streaming_load_max_mb:BE配置,默认10G,单位为MB,用户导入数据的最大限制。只能在be.conf中设置
<think>嗯,用户提供的这段代码是关于使用Spark将Hive数据导入到Doris表中的,但在执行过程中遇到了一个错误,提示“too many filtered rows”。首先,我需要分析这个错误的原因。根据Doris的文档,DATA_QUALITY_ERROR通常和数据质量有关,比如字段类型不匹配、数据格式错误或者违反约束条件。错误信息显示有5行被过滤,导致所有200行中的有效行数为0,所以插入失败了。 接下来,我要考虑用户可能的背景。用户可能是在进行数据迁移或ETL操作,使用Spark连接Hive和Doris。他们可能对DorisStream Load机制不太熟悉,或者在表结构设计、数据清洗方面存在问题。用户可能没有意识到Doris表的结构或约束与Hive视图的数据存在差异。 用户的需求不仅仅是解决当前错误,更希望理解错误原因,并学会如何预防类似问题。深层需求可能包括优化数据导入流程,确保数据一致性,以及提高处理大数据量时的效率。 接下来,我需要分步骤思考解决方案。首先,检查Doris表结构是否与Hive视图一致,包括字段类型、长度、是否允许NULL等。例如,Hive中的字符串可能在Doris中被定义为VARCHAR,但长度不够导致截断或过滤。其次,查看Doris表的约束,比如唯一键、聚合模型是否导致数据冲突。例如,如果表是聚合模型,重复键的数据可能被合并,但某些情况下可能引发问题。然后,检查数据中的NULL值,是否在Doris表中被标记为不允许NULL却没有处理。此外,数据格式如日期时间格式是否匹配,例如Hive的TIMESTAMP和Doris的DATETIME格式是否一致。 另外,用户提到使用Stream Load,而错误信息中的ErrorURL提供了详细的错误日志,用户需要访问该URL查看具体的过滤原因。可能因为权限问题无法直接访问,需要指导用户如何获取这些日志,或者调整Doris的配置以便记录更详细的错误信息。 此外,可以建议用户在导入前进行数据预览和验证,比如在Spark中执行Hive视图的查询,检查前几行数据是否符合Doris表的要求。还可以增加数据清洗步骤,处理异常值、空值或格式不符的数据。例如,使用CASE语句转换NULL,或者使用CAST函数转换数据类型。 最后,调整Stream Load的参数可能有助于解决问题,比如增加超时时间或调整批量大小。但在这个案例中,问题更可能出在数据本身,而不是参数设置。用户可能需要综合运用这些方法,逐步排查和修复数据中的问题,才能成功导入数据。</think>从你提供的代码和错误信息来看,这是一个使用Spark将Hive数据导入Doris时遇到的**数据质量校验失败**问题。以下是逐步分析及解决方案: --- ### 一、错误原因分析 ``` Caused by: org.apache.doris.spark.exception.StreamLoadException: [DATA_QUALITY_ERROR]too many filtered rows ``` - **核心问题**:Doris数据写入时发现**过多数据不符合目标表约束**,导致过滤行数超过阈值。 - **关键指标**: - `NumberTotalRows=200`:尝试写入200行 - `NumberFilteredRows=5`:5行数据被过滤 - `NumberLoadedRows=0`:最终有效数据为0行(Doris默认如果过滤行数 > 0,则整个批次写入失败) --- ### 二、常见触发原因 1. **字段类型不匹配** - Hive字段类型与Doris表定义不一致(如Hive是`STRING`,Doris是`INT`) 2. **数据约束冲突** - Doris表定义了`NOT NULL`约束,但Hive数据存在`NULL` - 唯一键/主键重复 3. **数据格式异常** - 日期时间格式不兼容(如`2023/01/01` vs `2023-01-01`) - 数值越界(如Doris字段定义为`TINYINT`但Hive数据包含`1000`) 4. **聚合模型冲突** - 如果Doris表是聚合模型(Aggregate Key),重复Key的数据可能触发合并规则 --- ### 三、排查步骤 #### 1. 对比表结构 检查Doris表 `ic_fddw_mart.ads_oo_po_vehicle_model_state1_bi` 与 Hive视图 `ads_oo_po_vehicle_model_state_bi` 的字段定义: ```sql -- Doris表结构 DESC ic_fddw_mart.ads_oo_po_vehicle_model_state1_bi; -- Hive视图结构 DESC ic_dev15oc_mart.ads_oo_po_vehicle_model_state_bi; ``` 重点检查: - 字段类型(如`VARCHAR`长度是否足够) - 是否允许`NULL` - 主键/唯一键约束 #### 2. 查看错误详情 通过Doris返回的`ErrorURL`获取详细错误日志: ``` http://10.0.42.207:8040/api/_load_error_log?file=__shard_6/error_log_insert_stmt_a14de4ff2f2266cd-77dffd6e44b71bb8_a14de4ff2f2266cd_77dffd6e44b71bb8 ``` 此日志会明确标记**被过滤行的具体原因**(如字段类型转换失败、违反约束等)。 #### 3. 数据抽样验证 在Spark中抽样检查Hive数据: ```sql -- 检查NULL值 SELECT * FROM hive_view WHERE some_column IS NULL; -- 检查数值范围 SELECT MAX(some_number_column) FROM hive_view; -- 检查字符串长度 SELECT MAX(LENGTH(some_string_column)) FROM hive_view; ``` #### 4. 调整Doris容忍度(临时方案) 在`OPTIONS`中添加参数允许部分数据过滤: ```scala "doris.sink.properties.max_filter_ratio"="0.1" -- 允许最多10%的数据过滤 ``` > **注意**:需谨慎使用,仅建议在明确知道数据质量问题可接受时使用。 --- ### 四、解决方案 #### 方案1:修复数据质量 ```sql -- 在Hive视图中增加数据清洗逻辑 CREATE TEMP VIEW cleaned_hive_view AS SELECT CAST(col1 AS INT) AS col1, -- 强制类型转换 COALESCE(col2, 'unknown') AS col2, -- 处理NULL值 SUBSTR(col3, 1, 100) AS col3 -- 截断超长字符串 FROM hive_view; ``` #### 方案2:调整Doris表结构 ```sql -- 修改字段允许NULL ALTER TABLE doris_table MODIFY COLUMN col2 VARCHAR(255) NULL; -- 扩大字段长度 ALTER TABLE doris_table MODIFY COLUMN col3 VARCHAR(200); ``` #### 方案3:修改Stream Load配置 ```scala // 增加超时时间 "doris.sink.properties.timeout"="600" // 调小批次大小 "sink.batch.size"="1000" ``` --- ### 五、预防措施 1. **数据迁移前校验**:使用`WHERE 1=0`空跑测试表结构兼容性 2. **启用严格模式**:在Doris中设置`enable_insert_strict=true` 3. **添加ETL中间层**:通过Spark进行数据清洗和类型转换 --- ### 六、技术原理补充 Doris通过**Stream Load**机制接收数据时,会进行以下校验: 1. 数据格式解析(JSON/CSV等) 2. 类型强校验(如非数值写入`INT`字段直接失败) 3. 约束检查(`NOT NULL`、唯一键等) 4. 对于聚合模型,执行`REPLACE`/`SUM`等预聚合操作 可通过以下公式理解过滤阈值: $$ \text{过滤比例} = \frac{\text{NumberFilteredRows}}{\text{NumberTotalRows}} $$ 当该比例超过`max_filter_ratio`时,整个批次写入失败。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值