如何使用Solr Cell批量索引HTML文件?

时间:2016-02-29 01:39:17

标签: java solr solrj

我有一个包含2亿个HTML文件的目录(不要看我,我没有造成这个混乱,我只需要处理它)。我需要将该目录中的每个HTML文件编入索引。我一直在阅读有关完成工作的指南,而且我现在有了一些事情要做。大约一个小时后,我有大约100k的索引,这意味着大约需要85天。

我将文件索引到独立的Solr服务器,在c4.8xlarge AWS EC2实例上运行。这是free -m的输出,其中Solr服务器正在运行,我编写的索引器也在运行:

             total       used       free     shared    buffers     cached
Mem:         60387      12981      47405          0         19       4732
-/+ buffers/cache:       8229      52157
Swap:            0          0          0

正如您所看到的,我在资源上做得非常好。我在Solr配置中将maxWarmingSearchers的数量增加到200,因为我收到了错误:

  

maxWarmingSearchers = 2的超出限制,稍后再试

好吧,但我认为增加这个限制确实是正确的方法。我认为问题在于,对于每个文件,我正在进行提交,我应该批量执行此操作(例如50k文件/提交),但我并不完全确定如何调整此代码,以及我看到的每个例子一次只能处理一个文件。我真的需要尽我所能让这次运行尽快,因为我没有85天等待在Solr中获取数据。

这是我的代码:

Index.java

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;


public class Index {

    public static void main(String[] args) {
        String directory = "/opt/html";
        String solrUrl = "URL";
        final int QUEUE_SIZE = 250000;
        final int MAX_THREADS = 300;

        BlockingQueue<String> queue = new LinkedBlockingQueue<>(QUEUE_SIZE);


        SolrProducer producer = new SolrProducer(queue, directory);
        new Thread(producer).start();

        for (int i = 1; i <= MAX_THREADS; i++)
            new Thread(new SolrConsumer(queue, solrUrl)).start();
    }
}

Producer.java

import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.BlockingQueue;

public class SolrProducer implements Runnable {
    private BlockingQueue<String> queue;
    private String directory;

    public SolrProducer(BlockingQueue<String> queue, String directory) {
        this.queue = queue;
        this.directory = directory;
    }

    @Override
    public void run() {
        try {
            Path path = Paths.get(directory);
            Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    if (!attrs.isDirectory()) {
                        try {
                            queue.put(file.toString());
                        } catch (InterruptedException e) {
                        }
                    }
                    return FileVisitResult.CONTINUE;
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

Consumer.java

import co.talentiq.common.net.SolrManager;
import org.apache.solr.client.solrj.SolrServerException;

import java.io.IOException;
import java.util.concurrent.BlockingQueue;

public class SolrConsumer implements Runnable {
    private BlockingQueue<String> queue;
    private static SolrManager sm;

    public SolrConsumer(BlockingQueue<String> queue, String url) {
        this.queue = queue;
        if (sm == null)
            this.sm = new SolrManager(url);
    }

    @Override
    public void run() {
        try {
            while (true) {
                String file = queue.take();
                sm.indexFile(file);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (SolrServerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

SolrManager.java

import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.request.AbstractUpdateRequest;
import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;

import java.io.File;
import java.io.IOException;
import java.util.UUID;

public class SolrManager {
    private static String urlString;
    private static SolrClient solr;

    public SolrManager(String url) {
        urlString = url;
        if (solr == null)
            solr = new HttpSolrClient(url);
    }

    public void indexFile(String fileName) throws IOException, SolrServerException {
        ContentStreamUpdateRequest up = new ContentStreamUpdateRequest("/update/extract");
        String solrId = UUID.randomUUID().toString();
        up.addFile(new File(fileName), solrId);
        up.setParam("literal.id", solrId);
        up.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true);
        solr.request(up);
    }

}

2 个答案:

答案 0 :(得分:0)

您可以使用up.setCommitWithin(10000);使Solr至少每十秒自动提交一次。增加值以使Solr每分钟(60000)或每十分钟(600000)提交一次。删除显式提交(setAction(..))。

另一种选择是configure autoCommit in your configuration file

您也可以通过从Solr移出HTML提取流程(并提交要编制索引的文本)或扩展您要发布的服务器数量来更快地编制索引(群集中的更多节点) )。

答案 1 :(得分:0)

我猜你在索引文档时不会并行搜索索引。所以这是你可以做的事情。

  • 您可以在solrconfig.xml中配置自动提交选项。可以根据文档数/时间间隔来完成。对你来说,文件数量选项会更有意义。

  • 在ContentStreamUpdateRequest对象中删除对setAction()方法的调用。您可以维护对indexFile()方法的调用次数。如果它达到25000/10000(基于您的堆,您可以限制计数),那么仅针对该索引调用,您可以使用SolrClient对象(如solr.commit())执行提交。因此,对于指定的计数,将提交一次。

让我知道结果。祝你好运!