我需要从mysql数据库和索引文档(大约1000个文档)导入大量数据。 在索引过程中,我需要通过向外部Apache Stanbol服务器发送增强请求来对字段进行特殊处理。 我在solrconfig.xml中配置了dataimport-handler以使用更新链中的StanbolContentProcessor,如下所示;
<updateRequestProcessorChain name="stanbolInterceptor">
<processor class="com.solr.stanbol.processor.StanbolContentProcessorFactory"/>
<processor class="solr.RunUpdateProcessorFactory" />
</updateRequestProcessorChain>
<requestHandler name="/dataimport" class="solr.DataImportHandler">
<lst name="defaults">
<str name="config">data-config.xml</str>
<str name="update.chain">stanbolInterceptor</str>
</lst>
</requestHandler>
我的示例data-config.xml如下所示;
<dataConfig>
<dataSource type="JdbcDataSource" driver="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/solrTest"
user="test" password="test123" batchSize="1" />
<document name="stanboldata">
<entity name="stanbolrequest" query="SELECT * FROM documents">
<field column="id" name="id" />
<field column="content" name="content" />
<field column="title" name="title" />
</entity>
</document>
</dataConfig>
当运行包含大约1000个文档的大型导入时,我的stanbol服务器出现故障,我怀疑是由于上面的Solr Stanbolnterceptor负载过重。 我想分批限制dataimport,以便Stanbol可以同时处理可管理数量的请求。
使用data-config中的dataSource元素中的batchSize参数是否可以实现?
有人可以提出一些想法来限制Solr中的dataimport加载吗?
这是我在/ dataimport期间处理Stanbol请求的自定义UpdateProcessor类
public class StanbolContentProcessorFactory extends
UpdateRequestProcessorFactory {
public static final String NLP_ORGANIZATION = "nlp_organization";
public static final String NLP_PERSON = "nlp_person";
public static final String[] STANBOL_REQUEST_FIELDS = { "title", "content" };
public static final String STANBOL_ENDPOINT = "http://localhost:8080/enhancer";
@Override
public UpdateRequestProcessor getInstance(SolrQueryRequest req,
SolrQueryResponse res, UpdateRequestProcessor next) {
return new StanbolContentProcessor(next);
}
class StanbolContentProcessor extends UpdateRequestProcessor {
public StanbolContentProcessor(UpdateRequestProcessor next) {
super(next);
}
@Override
public void processAdd(AddUpdateCommand cmd) throws IOException {
SolrInputDocument doc = cmd.getSolrInputDocument();
String request = "";
for (String field : STANBOL_REQUEST_FIELDS) {
if (null != doc.getFieldValue(field)) {
request += (String) doc.getFieldValue(field) + ". ";
}
}
try {
EnhancementResult result = stanbolPost(request, getBaseURI());
Collection<TextAnnotation> textAnnotations = result
.getTextAnnotations();
// extracting text annotations
Set<String> personSet = new HashSet<String>();
Set<String> orgSet = new HashSet<String>();
for (TextAnnotation text : textAnnotations) {
String type = text.getType();
String selectedText = text.getSelectedText();
if (null != type && null != selectedText) {
if (type.equalsIgnoreCase(StanbolConstants.DBPEDIA_PERSON)
|| type.equalsIgnoreCase(StanbolConstants.FOAF_PERSON)) {
personSet.add(selectedText);
} else if (type
.equalsIgnoreCase(StanbolConstants.DBPEDIA_ORGANIZATION)
|| type.equalsIgnoreCase(StanbolConstants.FOAF_ORGANIZATION)) {
orgSet.add(selectedText);
}
}
}
for (String person : personSet) {
doc.addField(NLP_PERSON, person);
}
for (String org : orgSet) {
doc.addField(NLP_ORGANIZATION, org);
}
cmd.solrDoc = doc;
super.processAdd(cmd);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
private EnhancementResult stanbolPost(String request, URI uri) {
Client client = Client.create();
WebResource webResource = client.resource(uri);
ClientResponse response = webResource.type(MediaType.TEXT_PLAIN)
.accept(new MediaType("application", "rdf+xml"))
.entity(request, MediaType.TEXT_PLAIN)
.post(ClientResponse.class);
int status = response.getStatus();
if (status != 200 && status != 201 && status != 202) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatus());
}
String output = response.getEntity(String.class);
// Parse the RDF model
Model model = ModelFactory.createDefaultModel();
StringReader reader = new StringReader(output);
model.read(reader, null);
return new EnhancementResult(model);
}
private static URI getBaseURI() {
return UriBuilder.fromUri(STANBOL_ENDPOINT).build();
}
}
答案 0 :(得分:3)
batchSize
选项用于批量检索数据库表的行,以减少内存使用(通常用于防止在运行数据导入处理程序时内存不足)。虽然较低的批量可能较慢,但该选项并不打算影响导入过程的速度。
我的建议是以其他方式限制请求,例如使用防火墙规则。如果您使用的是Linux并且可以访问Netfilter,则可以运行类似以下命令的内容:
iptables -A INPUT -p tcp --dport 12345 -m limit --limit 10/s -j ACCEPT
其中'12345'是Stanbol端口,'10 / s'是每秒接受的数据包数。
答案 1 :(得分:3)
Mowgli是对的,batchsize
对此没有帮助。由于大多数人反过来解决了这个问题(比如My dataimport is too slow, please help
),Solr中没有这样的事情。至少我没有意识到。
就个人而言,我不会选择配置您的Linux系统来为您处理限制。如果您从一个阶段移动到另一个阶段,或者您迁移到另一个服务器 - 当您需要为此记住时。如果人们在系统生命周期内发生变化,他们就不会知道这一点。
因此,我不知道您StanbolContentProcessorFactory
的代码,但正如已经提到in your other question,它似乎是自定义代码。由于它是您的自定义代码,您可以在其中添加节流机制。要详细说明,我需要一些代码来查看。
<强>更新强>
Solr确实有谷歌的番石榴,所以我会使用RateLimiter as proposed here。如果您使用Maven构建这意味着,您可以使用范围provided
。如果您没有使用Maven,则无需使用Solr的lib文件夹制作fatjar或放置番石榴。
import com.google.common.util.concurrent.RateLimiter;
public class StanbolContentProcessorFactory extends
UpdateRequestProcessorFactory {
// ...
// add a rate limiter to throttle your requests
// this setting would allow 10 requests per second
private RateLimiter throttle = RateLimiter.create(0.1);
// ...
private EnhancementResult stanbolPost(String request, URI uri) {
Client client = Client.create();
// this will throttle your requests
throttle.acquire();
WebResource webResource = client.resource(uri);
ClientResponse response = webResource.type(MediaType.TEXT_PLAIN)
.accept(new MediaType("application", "rdf+xml"))
.entity(request, MediaType.TEXT_PLAIN)
.post(ClientResponse.class);
int status = response.getStatus();
if (status != 200 && status != 201 && status != 202) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatus());
}
String output = response.getEntity(String.class);
// Parse the RDF model
Model model = ModelFactory.createDefaultModel();
StringReader reader = new StringReader(output);
model.read(reader, null);
return new EnhancementResult(model);
}