【问题标题】:Indexing huge data (~12 million rows) from postgreSQL to Elasticsearch is VERY SLOW从 postgreSQL 到 Elasticsearch 索引大量数据(约 1200 万行)非常慢
【发布时间】:2019-04-29 03:50:48
【问题描述】:

我正在使用postgreSQL,我正在尝试将Elasticsearch 的功能引入我们的系统。我正在使用此算法将数据(每次 1000 行 数据)批量插入 Elasticsearch。问题是它非常缓慢,仅 280 000 行数据就需要大约 15 小时

据我估计,只需要 26 天 不间断地完成对这个表的索引(有大约 1200 万条记录)。

是否有可能以某种方式优化这种方法并创建一种更快的方法?这就是我目前正在做的事情:

public function run()
    {
        $es_client = new \Elastica\Client();
        $es_index = $es_client->getIndex("vehicle");
        $es_type = $es_index->getType("_doc");

        $vehicle_ins = new Vehicle;

        $step = 1000;
        $min_vehicle_id = $vehicle_ins->query()->min('id');
        $max_vehicle_id = $vehicle_ins->query()->max('id');

        $insert_counter = 1;

        $docs = [];

        for ($i = $min_vehicle_id ; $i <= $max_vehicle_id ; $i += $step) {
            $x = $i;
            $y = $i + $step;

            $vehicles = $vehicle_ins->query()
                ->where('id', '>=', $x)
                ->where('id', '<', $y)
                ->get();

            foreach ($vehicles as $vehicle) {

                $docs[] = new \Elastica\Document(
                    $vehicle->id,
                    [
                        // implementing my columns (91 columns)
                    ]);

                echo ".";

                if ($insert_counter % $step == 0) {
                    $es_type->addDocuments($docs);
                    $es_type->getIndex()->refresh();
                    $docs = [];
                    echo "\n";
                    echo $step . " rows inserted!";
                    echo "\n";
                }

                $insert_counter++;

            }
        }
        if (!empty($docs)) {
            $es_type->addDocuments($docs);
            $es_type->getIndex()->refresh();
            $docs = [];
        }
    }

P.S:我使用elasticaElasticsearch 一起工作,应用程序位于Laravel 5.7 中,postgreSQL 作为主数据库。

P.S:ElasticSearch website 中也提出了这种方法,但对于我正在处理的数据量来说,它仍然太慢了。

【问题讨论】:

  • 每次addDocument操作后是否需要调用refresh?此外,laravel 有一个内置的 chunk 方法,可以为你“分页”你的结果,所以不需要那种选择
  • -&gt;where('id', '&gt;=', $x)-&gt;where('id', '&lt;', $y) 如果没有 id 索引可能会很慢,而且肯定会比内部使用 limit ... offsetskip($x)-&gt;take($step) 慢,并且不需要对行数据进行任何实际比较.

标签: php laravel postgresql elasticsearch optimization


【解决方案1】:

问题是因为我的Vehicle model 内部的一些方法在从数据库中获取每个属性后对它们进行了一些更改,这些不需要的更改使过程非常缓慢。

解决方案是使用Laravel DB facade 查询数据,直到那些属性更改器方法被删除或从车辆模型转移到其他地方。

所以查询应该是这样的:

$min_vehicle_id = \Illuminate\Support\Facades\DB::table('vehicle')->min('id');
$max_vehicle_id = \Illuminate\Support\Facades\DB::table('vehicle')->max('id');

还有这个用于获取数据:

$vehicles = \Illuminate\Support\Facades\DB::table('vehicle')
                ->where('id', '>=', $x)
                ->where('id', '<', $y)
                ->get();

【讨论】:

    【解决方案2】:

    尝试将mapping 添加到您的索引。还要检查您是否需要分析每个字段 - https://www.elastic.co/guide/en/elasticsearch/reference/2.3/mapping-index.html

    【讨论】:

    • 我现在不需要做任何分析,因为我现在只是想索引数据库中的所有内容。但是关于映射,你认为它真的提高了速度吗?因为 Elasticsearch 插入 1000 条数据的部分非常快。创建数据并准备好插入时速度很慢
    • 这里有更多提示 -elastic.co/guide/en/elasticsearch/reference/5.3/…(增加刷新间隔,禁用刷新和副本以进行初始加载,使用自动生成的 id)
    猜你喜欢
    • 2016-11-10
    • 2014-07-15
    • 1970-01-01
    • 2014-10-08
    • 1970-01-01
    • 1970-01-01
    • 2015-02-06
    • 2020-05-10
    相关资源
    最近更新 更多