如何使用batchSize限制Solr中的dataimports

时间:2013-11-26 08:52:50

标签: solr dataimporthandler apache-stanbol

我需要从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();
    }

}

2 个答案:

答案 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);
}