Spring batch 使用spring批处理处理大型文件
我有一个大文件,可能包含100K到500K的记录。我计划使用面向块的处理,我的想法是 1) 根据每个文件中的计数(比如10K),将大文件拆分为小文件 2) 如果有10万条记录,那么我将得到10个文件,每个文件包含10万条REOCRD 3) 我想分区这10个文件,并希望使用5个线程处理。我正在考虑使用customMultiResourcePartioner 4) 这5个线程应该处理split进程中创建的所有10个文件 5) 我不想创建与文件计数相同数量的线程,因为在这种情况下,我可能会面临内存问题。我想看的是,无论我想用5个线程处理多少个文件(我可以根据需要增加) 专家您能告诉我这可以通过使用spring batch实现吗?如果是,请共享指针或参考实现 提前谢谢 工作作业配置xmlSpring batch 使用spring批处理处理大型文件,spring-batch,Spring Batch,我有一个大文件,可能包含100K到500K的记录。我计划使用面向块的处理,我的想法是 1) 根据每个文件中的计数(比如10K),将大文件拆分为小文件 2) 如果有10万条记录,那么我将得到10个文件,每个文件包含10万条REOCRD 3) 我想分区这10个文件,并希望使用5个线程处理。我正在考虑使用customMultiResourcePartioner 4) 这5个线程应该处理split进程中创建的所有10个文件 5) 我不想创建与文件计数相同数量的线程,因为在这种情况下,我可能会面临内存问题
<description>Spring Batch File Chunk Processing</description>
<import resource="../config/batch-context.xml" />
<batch:job id="file-partition-batch" job-repository="jobRepository" restartable="false">
<batch:step id="master">
<batch:partition partitioner="partitioner" handler="partitionHandler" />
</batch:step>
</batch:job>
<batch:step id="slave">
<batch:tasklet>
<batch:chunk reader="reader" processor="compositeProcessor"
writer="compositeWriter" commit-interval="5">
</batch:chunk>
</batch:tasklet>
</batch:step>
<bean id="partitionHandler" class="org.springframework.batch.core.partition.support.TaskExecutorPartitionHandler">
<property name="taskExecutor" ref="taskExecutor"/>
<property name="step" ref="slave" />
<property name="gridSize" value="5" />
</bean>
<bean id="partitioner" class="com.poc.partitioner.FileMultiResourcePartitioner">
<property name="resources" value="file:/Users/anupghosh/Documents/Spring_Batch/FilePartitionBatch/*.txt" />
<property name="threadName" value="feed-processor" />
</bean>
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="5" />
</bean>
<bean id="reader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
<property name="resource" value="#{stepExecutionContext['fileName']}" />
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer">
<bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="delimiter" value="|"/>
<property name="names" value="key,docName,docTypCD,itemType,itemNum,launchDate,status" />
</bean>
</property>
<property name="fieldSetMapper">
<bean class="com.poc.mapper.FileRowMapper" />
</property>
</bean>
</property>
</bean>
<bean id="validatingProcessor" class="org.springframework.batch.item.validator.ValidatingItemProcessor">
<constructor-arg ref="feedRowValidator" />
</bean>
<bean id="feedProcesor" class="com.poc.processor.FeedProcessor" />
<bean id="compositeProcessor" class="org.springframework.batch.item.support.CompositeItemProcessor" scope="step">
<property name="delegates">
<list>
<ref bean="validatingProcessor" />
<ref bean="feedProcesor" />
</list>
</property>
</bean>
<bean id="recordDecWriter" class="com.poc.writer.RecordDecWriter" />
<bean id="reconFlatFileCustomWriter" class="com.poc.writer.ReconFileWriter">
<property name="reconFlatFileWriter" ref="reconFlatFileWriter" />
</bean>
<bean id="reconFlatFileWriter" class="org.springframework.batch.item.file.FlatFileItemWriter" scope="step">
<property name="resource" value="file:/Users/anupghosh/Documents/Spring_Batch/recon-#{stepExecutionContext[threadName]}.txt" />
<property name="shouldDeleteIfExists" value="true" />
<property name="lineAggregator">
<bean class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
<property name="delimiter" value="|" />
<property name="fieldExtractor">
<bean class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
<property name="names" value="validationError" />
</bean>
</property>
</bean>
</property>
</bean>
<bean id="compositeWriter" class="org.springframework.batch.item.support.CompositeItemWriter">
<property name="delegates">
<list>
<ref bean="recordDecWriter" />
<ref bean="reconFlatFileCustomWriter" />
</list>
</property>
</bean>
<bean id="feedRowValidator" class="org.springframework.batch.item.validator.SpringValidator">
<property name="validator">
<bean class="com.poc.validator.FeedRowValidator"/>
</property>
</bean>
Spring批处理文件块处理
能够使用MultiResourcePartitioner解决这个问题。下面是java配置
@Bean
public Partitioner partitioner() {
MultiResourcePartitioner partitioner = new MultiResourcePartitioner();
ClassLoader cl = this.getClass().getClassLoader();
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(cl);
Resource[] resources = resolver.getResources("file:" + filePath + "/"+"*.csv");
partitioner.setResources(resources);
partitioner.partition(10);
return partitioner;
}
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setMaxPoolSize(4);
taskExecutor.afterPropertiesSet();
return taskExecutor;
}
@Bean
@Qualifier("masterStep")
public Step masterStep() {
return stepBuilderFactory.get("masterStep")
.partitioner(ProcessDataStep())
.partitioner("ProcessDataStep",partitioner())
.taskExecutor(taskExecutor())
.listener(pcStressStepListener)
.build();
}
@Bean
@Qualifier("processData")
public Step processData() {
return stepBuilderFactory.get("processData")
.<pojo, pojo> chunk(5000)
.reader(reader)
.processor(processor())
.writer(writer)
.build();
}
@Bean(name="reader")
@StepScope
public FlatFileItemReader<pojo> reader(@Value("#{stepExecutionContext['fileName']}") String filename) {
FlatFileItemReader<pojo> reader = new FlatFileItemReader<>();
reader.setResource(new UrlResource(filename));
reader.setLineMapper(new DefaultLineMapper<pojo>() {
{
setLineTokenizer(new DelimitedLineTokenizer() {
{
setNames(FILE HEADER);
}
});
setFieldSetMapper(new BeanWrapperFieldSetMapper<pojo>() {
{
setTargetType(pojo.class);
}
});
}
});
return reader;
}
@Bean
公共分区器分区器(){
MultiResourcePartitioner partitioner=新的MultiResourcePartitioner();
ClassLoader cl=this.getClass().getClassLoader();
ResourcePatternResolver解析器=新路径匹配ResourcePatternResolver(cl);
Resource[]resources=resolver.getResources(“文件:“+filePath+”/“+”*.csv”);
partitioner.setResources(资源);
分区器。分区(10);
返回分区器;
}
@豆子
公共任务执行器任务执行器(){
ThreadPoolTaskExecutor taskExecutor=新的ThreadPoolTaskExecutor();
taskExecutor.setMaxPoolSize(4);
taskExecutor.AfterPropertieSet();
返回任务执行器;
}
@豆子
@限定词(“主步骤”)
公共步骤masterStep(){
return stepBuilderFactory.get(“masterStep”)
.partitioner(ProcessDataStep())
.partitioner(“ProcessDataStep”,partitioner())
.taskExecutor(taskExecutor())
.listener(PCStepListener)
.build();
}
@豆子
@限定符(“processData”)
公共步骤processData(){
返回stepBuilderFactory.get(“processData”)
.chunk(5000)
.读卡器(读卡器)
.processor(处理器())
.作者(作者)
.build();
}
@Bean(name=“reader”)
@步进镜
公共FlatFileItemReader读取器(@Value(“#{stepExecutionContext['fileName']}”)字符串文件名){
FlatFileItemReader=新的FlatFileItemReader();
setResource(新的UrlResource(文件名));
reader.setLineMapper(新的DefaultLineMapper(){
{
setLineTokenizer(新的DelimitedLineTokenizer(){
{
设置名称(文件头);
}
});
setFieldSetMapper(新的BeanRapperFieldSetMapper(){
{
setTargetType(pojo.class);
}
});
}
});
返回读取器;
}
您确实正确地安排了流程。您的具体问题是什么?感谢@MichaelMinella在短时间内做出回应。我的问题是:如果在分割处理后我有10个文件(可能更多),我将如何使用5个线程处理这些文件?更具体地说,我将如何对这些文件进行分区,以便5个线程将处理所有这10个文件。MultiResourcePartitioner
是创建分区的正确方法。从那里,使用TaskExecutionPartitionHandler
,您可以通过TaskExecutor
的配置来控制使用了多少线程。默认情况下,它使用SyncTaskExecutor
,但我们希望您配置其他类似ThreadPoolTaskExecutor
。在该TaskExecutor
中,您可以配置最大线程数等。非常感谢@MichaelMinella遵照您的建议,我终于让它工作了。我感谢你的帮助。我已经编辑了我的答案,并添加了我的作业配置xml的工作版本,因为注释中存在大小限制。也许这对某人有用。请让我知道如何接受“答案”@Anup您是如何分割文件的?还需要添加taskExecutor.setCorePoolSize(4)和taskExecutor.setQueueCapacity(8)以使多线程工作。