SOLR—从csv文件导入2000万个文档的最佳方法

SOLR—从csv文件导入2000万个文档的最佳方法,csv,import,solr,bulkinsert,dataimporthandler,Csv,Import,Solr,Bulkinsert,Dataimporthandler,我目前的任务是找出在solr中加载数百万文档的最佳方法。 数据文件是以csv格式从数据库导出的 目前,我正在考虑将文件拆分为较小的文件,并在使用curl发布较小的文件时使用脚本 我注意到,如果发布大量数据,大多数情况下请求都会超时 我正在寻找数据导入器,它似乎是一个不错的选择 您还有其他想法吗 谢谢一定要先把它们加载到一个普通的数据库中。有各种各样的工具来处理CSV(例如),所以应该很容易。使用也非常简单,因此这似乎是加载数据最无摩擦的方式。这种方法也会更快,因为您不会有不必要的网络/HTTP开

我目前的任务是找出在solr中加载数百万文档的最佳方法。 数据文件是以csv格式从数据库导出的

目前,我正在考虑将文件拆分为较小的文件,并在使用curl发布较小的文件时使用脚本

我注意到,如果发布大量数据,大多数情况下请求都会超时

我正在寻找数据导入器,它似乎是一个不错的选择

您还有其他想法吗


谢谢

一定要先把它们加载到一个普通的数据库中。有各种各样的工具来处理CSV(例如),所以应该很容易。使用也非常简单,因此这似乎是加载数据最无摩擦的方式。这种方法也会更快,因为您不会有不必要的网络/HTTP开销。

除非数据库已经是您的解决方案的一部分,否则我不会给您的解决方案增加额外的复杂性。引用是您的servlet容器发出会话超时

在我看来,您有两个选择(按照我的偏好顺序):

增加容器超时 增加容器超时时间。((“maxIdleTime”参数,如果您使用的是嵌入式Jetty实例)

我想你只是偶尔索引这么大的文件?临时增加超时可能只是最简单的选择

分割文件 下面是执行此任务的简单unix脚本(将文件拆分为500000行块):

解析文件并分块加载 下面的groovy脚本使用opencsv和solrj解析CSV文件,并每500000行将更改提交给Solr

import au.com.bytecode.opencsv.CSVReader

import org.apache.solr.client.solrj.SolrServer
import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer
import org.apache.solr.common.SolrInputDocument

@Grapes([
    @Grab(group='net.sf.opencsv', module='opencsv', version='2.3'),
    @Grab(group='org.apache.solr', module='solr-solrj', version='3.5.0'),
    @Grab(group='ch.qos.logback', module='logback-classic', version='1.0.0'),
])

SolrServer server = new CommonsHttpSolrServer("http://localhost:8983/solr/");

new File("data.csv").withReader { reader ->
    CSVReader csv = new CSVReader(reader)
    String[] result
    Integer count = 1
    Integer chunkSize = 500000

    while (result = csv.readNext()) {
        SolrInputDocument doc = new SolrInputDocument();

        doc.addField("id",         result[0])
        doc.addField("name_s",     result[1])
        doc.addField("category_s", result[2])

        server.add(doc)

        if (count.mod(chunkSize) == 0) {
            server.commit()
        }
        count++
    }
    server.commit()
}
在Solr4.0(目前处于BETA版)中,可以使用UpdateHandler直接导入本地目录中的CSV。从中修改示例

这将从本地位置流式传输文件,因此无需将其分块并通过HTTP发布。

ConcurrentUpdateSolrServer
可以/应该用于批量更新

Javadocs有些不正确(,):

ConcurrentUpdateSolrServer缓冲所有添加的文档并将它们写入打开的HTTP连接


它不会无限期地进行缓冲,但最多可达到
int queueSize
,这是一个构造函数参数。

以上回答很好地解释了单机的摄取策略

如果您有大数据基础设施,并且希望实现分布式数据摄取管道,那么就没有更多的选择了

  • 使用sqoop将数据带到hadoop中,或者在hadoop中手动放置csv文件
  • 使用以下连接器之一接收数据:
  • 附言:

    • 确保没有防火墙阻止客户端节点和solr/solrcloud节点之间的连接
    • 为数据摄取选择正确的目录工厂,如果不需要近实时搜索,则使用
      StandardDirectoryFactory
    • 如果在摄取期间客户端日志中出现以下异常,请在
      solrconfig.xml
      文件中调整
      autoCommit
      autoSoftCommit
      配置
    SolrServerException:没有可用的实时SolrServer来处理此问题 请求


    马克,谢谢你的详细回答。这和我想弄明白的是一致的。我将有巨大的负荷作为第一次和更新增量每小时左右。我想我知道第一批货的选择。但是,我不确定什么是最易于管理的更新过程。我正在寻找可配置的健壮更新过程。任何关于这方面的信息都将不胜感激。谢谢。我建议为新文件创建一个“输入”目录,并在索引后将文件移动到“已处理”目录中。简单易维护。。。。然而。。。。你说CSV文件来自数据库?在这种情况下,如果您可以访问数据库,那么您可能需要更好地使用DIH处理程序。文件将从数据库中取出。不确定加载它们的目的是什么?好的,然后使用数据导入处理程序直接读取它们。这个选项有什么问题吗?+1我做了一些快速性能测试,DIH的性能比批量提交好一个数量级。但这只是第一印象。当数据库位于与安装Solr的位置不同的网络位置时,DIH无法处理拉取大量数据。套接字连接超时随之发生。必须使用opencsv将数据从数据库拉入csv文件中,并将其分成小块。然后使用FileListenityProcessor和LineEntityProcessor对数据进行索引进入Solr。@Vijay这听起来更像是网络基础设施/DB配置的问题,而不是DIH或Solr的问题。UpdateHandler与DataImportHandler的性能如何?在这两种情况下,输入都是CSV。我没有运行任何基准测试,但DataImportHandler的性能非常好。我们做了大约2000万条记录,在大约一小时内得到了大约7GB的索引(经过优化)。此外,在将数据添加到索引之前,我们还必须对数据进行一些转换,因此无法使用UpdateHandler进行转换。谢谢!我也在做这个,它就像一个符咒。约50万条记录(大小为8gb),耗时约40分钟。
    import au.com.bytecode.opencsv.CSVReader
    
    import org.apache.solr.client.solrj.SolrServer
    import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer
    import org.apache.solr.common.SolrInputDocument
    
    @Grapes([
        @Grab(group='net.sf.opencsv', module='opencsv', version='2.3'),
        @Grab(group='org.apache.solr', module='solr-solrj', version='3.5.0'),
        @Grab(group='ch.qos.logback', module='logback-classic', version='1.0.0'),
    ])
    
    SolrServer server = new CommonsHttpSolrServer("http://localhost:8983/solr/");
    
    new File("data.csv").withReader { reader ->
        CSVReader csv = new CSVReader(reader)
        String[] result
        Integer count = 1
        Integer chunkSize = 500000
    
        while (result = csv.readNext()) {
            SolrInputDocument doc = new SolrInputDocument();
    
            doc.addField("id",         result[0])
            doc.addField("name_s",     result[1])
            doc.addField("category_s", result[2])
    
            server.add(doc)
    
            if (count.mod(chunkSize) == 0) {
                server.commit()
            }
            count++
        }
        server.commit()
    }
    
    curl http://localhost:8983/solr/update?stream.file=exampledocs/books.csv&stream.contentType=text/csv;charset=utf-8