我有一个包含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);
}
}
答案 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())执行提交。因此,对于指定的计数,将提交一次。
让我知道结果。祝你好运!