【elasticsearch】批量更新数据

这篇博客介绍了如何在PHP环境下,利用Yii 2框架和elasticsearch扩展进行批量数据更新,重点讲解了对应的Elasticsearch批量更新API的参数请求结构。

软件版本:

  • php 5.6.31
  • elasticsearch 6.1.1
  • Yii 2 框架

elasticsearch 扩展:

{
    "require": {
        "elasticsearch/elasticsearch": "~5.0"
    }
}

代码:

function actionArticle()
{
    $open_sites = Yii::$app->getDb()->createCommand(
        "select indicator from {{%site}} where status = 1 order by id asc"
    )->queryAll();
    if (empty($open_sites)) {
        return 0;
    }

    foreach ($open_sites as $open_site) {
        $indicator = $open_site['indicator'];
        $articles = Yii::$app->getDb()->createCommand(
            "select id, heat from {{%article_{$indicator}}} order by id asc"
        )->queryAll();
        if (empty($articles)) {
            continue;
        }

        $es_params = ['index' => $indicator, 'type' => 'doc'];
        $body = [];
        foreach ($articles as $article) {
            $article_id = $article['id'];
            $body[] = ['update' => ['_id' => "article_{$article_id}"]];
            $body[] = ['doc' => ['heat' => $article['heat']]];

            if (count($body) >= 2000) {
                $es_params['body'] = $body;
                // file_put_contents('es_bulk.log', print_r($es_params, true));die;
                Yii::$app->elasticsearch->client->bulk($es_params);

                $body = [];
            }
        }

        if (!empty($body)) {
            $es_params['body'] = $body;
            Yii::$app->elasticsearch->client->bulk($es_params);
        }
    }

    return 0;
}

对应 elasticsearch 批量更新 api 的参数请求结构:

Array
(
    [index] => cn
    [type] => doc
    [body] => Array
        (
            [0] => Array
                (
                    [update] => Array
                        (
                            [_id] => article_1
                        )

                )

            [1] => Array
                (
                    [doc] => Array
                        (
                            [heat] => 0.00
                        )

                )

            [2] => Array
                (
                    [update] => Array
                        (
                            [_id] => article_2
                        )

                )

            [3] => Array
                (
                    [doc] => Array
                        (
                            [heat] => 0.00
                        )

                )

            ...

        )

)

<think>我们在处理批量更新时需要使用Elasticsearch的helpers.bulk方法,同时构造特定的更新操作。根据引用[4],update操作需要两行:一行是元信息(包括操作类型、索引、id等),另一行是更新内容(使用doc指定部分字段更新,或使用script等)。另外,引用[3]中展示了bulk操作的响应格式,其中每个操作都有各自的返回状态。步骤:1.连接Elasticsearch(如引用[1]所示)。2.构造批量更新的操作列表,每个更新操作是一个字典,包含两个元素:一个是操作的元数据,另一个是更新内容的描述(如doc或script)。3.使用helpers.bulk执行批量操作。注意:在更新操作中,我们通常使用'_op_type'为'update',然后在数据部分提供'doc'(用于部分更新)或'script'(用于脚本更新)。示例:批量更新文档中某个字段的值。假设我们有一个索引为'my_index',类型为'my_type'(注意:在ES7及以上类型被弃用,通常使用_doc),我们要更新多个文档的某个字段。构造更新操作的动作列表:每个动作是一个字典,形如:{'_op_type':'update',#操作类型'_index':'index_name','_id':doc_id,'doc':{...}#要更新的字段}但请注意,引用[4]中提到:update操作由两行构成,第一行是元信息(包括操作类型、索引、id),第二行是更新数据(如doc、upsert、script)。在使用helpers.bulk时,我们不需要手动分两行,而是将每个操作表示为一个字典,并设置相应的键。在elasticsearch-py中,更新操作的格式为:{"_op_type":"update","_index":"index_name","_id":"document_id","doc":{"field1":"new_value1","field2":"new_value2"}}或者使用script:{"_op_type":"update","_index":"index_name","_id":"document_id","script":{"source":"ctx._source.field1=params.value","lang":"painless","params":{"value":"new_value"}}}然后,我们将这些操作组成的列表传递给helpers.bulk。另外,引用[2]提供了简单的查询示例,但我们现在关注更新。代码示例:假设我们要更新索引'my_index'中的一批文档,将每个文档的'status'字段更新为'active'。注意:在实际使用中,我们可能会根据查询结果来更新,但这里我们假设已经知道要更新的文档id。根据引用[1],首先连接Elasticsearch,然后使用helpers.bulk。我们使用以下步骤:1.导入必要的模块2.建立连接3.定义更新操作列表4.执行批量更新代码:"""fromelasticsearchimportElasticsearchfromelasticsearchimporthelpers#连接Elasticsearches=Elasticsearch(['localhost:9200'])#要执行的操作列表actions=[{"_op_type":"update","_index":"my_index","_id":"1",#文档ID"doc":{"status":"active"}},{"_op_type":"update","_index":"my_index","_id":"2","doc":{"status":"inactive"}}#可以添加更多更新操作]#使用helpers.bulk进行批量操作try:#执行批量操作success,failed=helpers.bulk(es,actions=actions,index='my_index',stats_only=True)print(f"Successfullyupdated{success}documents.")iffailed:print(f"Failedtoupdate{failed}documents.")exceptExceptionase:print(f"Anerroroccurred:{str(e)}")"""注意:stats_only参数设置为True时,只返回成功和失败的数量,不返回详细的错误信息。如果需要详细错误信息,可以将其设置为False。另外,引用[3]中展示了bulk操作的返回响应,其中每个操作都有状态。如果出现错误,可以捕获并处理。如果更新操作中需要条件更新(比如根据文档当前状态进行更新),那么可以使用'script'方式,并在script中编写逻辑。考虑到引用[4]中提到的,update操作的数据行可能是doc、upsert或script,所以我们可以根据需求选择。另外,如果文档不存在,更新操作会失败(除非你使用upsert)。如果想在更新时如果文档不存在则插入,可以加入'upsert'字段,例如:{"_op_type":"update","_index":"my_index","_id":"3","doc":{"status":"new"},"upsert":{"status":"new","other_field":"value"}}这样,如果文档不存在,就会插入upsert指定的文档。最后,根据用户需求,我们提供了批量更新的方法。相关问题:1.在Elasticsearch中如何进行条件更新?2.批量更新时如何处理错误?3.如何优化Elasticsearch批量更新的性能?4.在Python中如何监控Elasticsearch批量更新的进度?</think> 在 Python 中使用 Elasticsearch 进行批量更新数据,可以通过 `helpers.bulk()` 方法实现。以下是具体步骤和示例代码,参考了提供的引用内容: ### 步骤说明 1. **连接 Elasticsearch**:建立与 ES 实例的连接 2. **构造更新动作**:每个更新操作包含元数据(操作类型、索引、ID)和更新内容 3. **使用 `bulk` API**:通过批量接口提交操作 4. **处理响应**:检查执行结果和错误 ### 完整代码示例 ```python from elasticsearch import Elasticsearch from elasticsearch import helpers # 1. 连接ES实例(引用[1]) es = Elasticsearch(hosts=['localhost:9200']) # 2. 构造批量更新动作 update_actions = [ { "_op_type": "update", # 操作类型 "_index": "your_index", # 索引名 "_id": doc_id, # 文档ID "doc": {"field": "new_value"} # 更新字段(引用[4]) } for doc_id in [1, 2, 3] # 需要更新的文档ID列表 ] # 3. 执行批量更新(引用[3]) try: success_count, errors = helpers.bulk( es, actions=update_actions, stats_only=True # 仅返回计数,不返回详细错误 ) print(f"成功更新 {success_count} 条文档") except Exception as e: print(f"批量更新失败: {str(e)}") # 4. 处理错误(引用[3]展示的错误结构) if errors: print(f"部分更新失败,数量: {errors}") # 如需详细错误信息,移除 stats_only 参数并解析返回值 ``` ### 关键说明 1. **元数据格式**(引用[4]): - 每个更新操作需要两行数据: ``` {"update": {"_index":"index","_id":"1"}} {"doc": {"field":"new_value"}} ``` - 代码中通过 `_op_type` 和 `doc` 自动生成该格式 2. **更新内容类型**(引用[4]): ```python "doc": {"field": "value"} # 字段更新 "script": "ctx._source.counter++" # 脚本更新 "upsert": {"field": "default"} # 文档不存在时插入 ``` 3. **性能优化建议**: - 单批次文档数控制在 1000-5000 - 使用多线程/异步提交 - 启用 `refresh=False` 禁用实时刷新
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值