Маршрутизация данных в несколько файлов в средстве записи элементов на основе свойства элемента в качестве критерия

Я получаю список элементов в моем ридере.

В каждом объекте элемента есть свойство с именем Code, имеющее несколько возможных значений, неизвестных мне заранее.

1) Основываясь на значении Codein каждого элемента, я хочу записать этот конкретный элемент в выходной файл, относящийся к этому Code. Например, если Code моего текущего элемента - "abc", элемент должен быть записан в abc.txt в модуле записи.

2) Если в текущем элементе есть Code "xyz", для которого файл отсутствует, должен быть создан новый файл, и элемент должен перейти в этот файл.

3) Для всех таких нескольких файлов, созданных на основе Code, я также хочу добавить обратный вызов верхнего и нижнего колонтитула, чтобы ввести некоторые детали, например. количество элементов в каждом файле.

Возможно ли иметь писателя, который удовлетворяет выше 3 требованиям?

Я знаю, что с помощью multiresourceitemwriter можно разделить данные между несколькими выходными файлами. Но, насколько я знаю, это деление основано на количестве предметов. Например, первые 10 элементов в файле1, следующие 10 в файле2 и так далее.

Но как направить данные в выходные файлы на основе свойства элемента, как указано в моем вопросе?

Я хорошо знаком с Spring Batch и мне просто нужно небольшое руководство, так как я впервые сталкиваюсь с такой проблемой.

Спасибо за чтение!


person Vicky    schedule 17.09.2012    source источник
comment
сколько элементов вы ожидаете в файле (сейчас и в течение срока службы продукта)   -  person Michael Pralow    schedule 17.09.2012
comment
@MichaelLange: Информация, которую я сейчас имею в руках, я полагаю, что это будет около миллиона записей на файл.   -  person Vicky    schedule 18.09.2012
comment
@MichaelLange: сто тысяч записей в файле :)   -  person Vicky    schedule 18.09.2012


Ответы (6)


я бы попробовал хотя бы 2 стратегии

  1. пакет записывает все данные во временную таблицу базы данных, а простой инструмент/пакет/скрипт создает отдельные файлы - я не уверен в верхнем/нижнем колонтитуле, но, как всегда, можно сказать: «давайте сделаем это дешево»
  2. itemWriter создает и управляет необходимыми модулями записи на лету, возможно, с абстрактным предварительно настроенным модулем записи/компонентом в качестве шаблона, пока вы игнорируете сценарии перезапуска, это звучит «просто»
person Michael Pralow    schedule 18.09.2012
comment
stackoverflow.com/users/887235/vicky @vicky Не могли бы вы привести свою реализацию для справки! - person kondu; 23.09.2016

Если я правильно понимаю вашу проблему, вам нужно несколько предметов.

Во-первых, классификатор, реализующий классификатор интерфейс

public class ItemCodeClassifier {
    @Classifier
    public String classify(Item item) {
        return item.getCode().getKey();// returns "abc", "xyz"
    }
}

Вторая реализация маршрутизатора, использующая описанный выше метод.

<bean id="classifier"  class="org.springframework.batch.classify.BackToBackPatternClassifier">
    <property name="routerDelegate">
        <bean class="ItemCodeClassifier" />
    </property>
    <property name="matcherMap">
        <map>
        <entry key="abc" value-ref="abcItemWriter" />
        <entry key="xyz" value-ref="xyzItemWriter" />
        </map>
    </property>
</bean>

И, наконец, ClassifierCompositeItemWriter

<bean id="ItemWriter" class="org.springframework.batch.item.support.ClassifierCompositeItemWriter">
<property name="classifier" ref="classifier" />
</bean

Не компилировал вышеизложенное, но надеюсь, что это поможет.

person Serkan Arıkuşu    schedule 17.09.2012
comment
Я не могу использовать ваше решение, потому что ваше решение по своей сути предполагает, что количество писателей так много. Но в моей проблеме я заранее не знаю количество и тип писателей, поэтому я не могу заранее определить abcItemWriter/xyzItemWriter. - person Vicky; 18.09.2012
comment
Вам понадобятся динамические писатели. ItemReaders и ItemWriters создаются до начала шага, поэтому я сомневаюсь, что Spring Batch справится с этим. - person Serkan Arıkuşu; 18.09.2012

Ниже решение сработало для меня. Скомпилировал код, все работает.

Во-первых, вам понадобится классификатор. Либо реализуйте интерфейс Classifier, либо аннотируйте метод classify() с помощью @Classifier.

Здесь я использовал аннотацию.

public class MyClassifier {
    @Classifier
    public String classify(Policy pol) {
        return pol.getPolCode;// returns "01", "02"
    }
}

Добавьте bean-компонент классификатора

<bean id="myClassifier"  class="org.springframework.batch.classify.BackToBackPatternClassifier">
    <property name="routerDelegate">
        <bean class="MyClassifier" />
    </property>
    <property name="matcherMap">
        <map>
        <entry key="01" value-ref="pol01ItemWriter" />
        <entry key="02" value-ref="pol02ItemWriter" />
        </map>
    </property>
</bean>

Добавьте свой писательский компонент, как показано ниже.

<bean id="ItemWriter" class="org.springframework.batch.item.support.ClassifierCompositeItemWriter">
    <property name="myClassifier" ref="myClassifier" />
</bean>

Приведенный выше код может вызвать исключение WriterNotOpenException. Для этого вам нужно добавить пакет: поток к шагу.

<batch:step id="step1">
    <batch:tasklet>
        <batch:chunk reader="reader" processor="processor" writer="ItemWriter" commit-interval="3">
            <batch:streams>
                <batch:stream ref="pol01ItemWriter"/>
                <batch:stream ref="pol02ItemWriter"/>
            </batch:streams>
        </batch:chunk>
    </batch:tasklet>
</batch:step>
person Mukesh Sabde    schedule 25.10.2015

Другим вариантом было бы создание 3 списков, содержащих элементы, разделенные их кодом. Затем используйте другой шаг, чтобы записать эти списки в файловую систему.

Одним из преимуществ является то, что ваши элементы готовы к записи, поэтому вы можете использовать большой буфер для увеличения пропускной способности записи (конечно, в зависимости от вашего оборудования).

Если количество файлов, которые вы должны сгенерировать, является динамическим, я предлагаю вам писать их последовательно, чтобы избежать проблем с многопоточностью.

Вы не можете маршрутизировать элементы динамически. Итак, идея состоит в том, чтобы создать список элементов, маршрутизируемых самостоятельно, а затем работать с этими списками.

person Jean-Philippe Briend    schedule 17.09.2012

Конфигурация Java для модуля записи JDBC

Вот как я сделал это для JDBC Writer. У нас может быть аналогичная конфигурация для Flatfile Writer

 @Bean
    public ItemWriter<Person> itemWriter(DataSource dataSource) {
        BackToBackPatternClassifier classifier = new BackToBackPatternClassifier();
        classifier.setRouterDelegate(new AggGroupClassifier());
        classifier.setMatcherMap(new HashMap<String, ItemWriter<? extends Person>>() {
            {
                put("A", writerA(dataSource));
                put("B", writerB(dataSource));
                put("C", writerC(dataSource));

            }
        });
        ClassifierCompositeItemWriter<Person> writer = new ClassifierCompositeItemWriter<Person>();
        writer.setClassifier(classifier);
        return writer;      
        }


public class AggGroupClassifier {

    @Classifier
    public String classify(Person person) {
        return person.getAgeGroup();

    }
}
person Niraj Sonawane    schedule 05.12.2018

Я столкнулся с этой же проблемой сегодня утром. И, наконец, я обнаружил, что в настоящее время ClassifierCompositeItemWriter не поддерживает FlatFileItemWriter в качестве своего делегата ItemWriter в последней версии пакета Spring 2.1.9.

WriterNotOpenException выбрасывается, как показано ниже:

org.springframework.batch.item.WriterNotOpenException: Writer must be open before it can be written to
    at org.springframework.batch.item.file.FlatFileItemWriter.write(FlatFileItemWriter.java:236)
    at org.springframework.batch.item.support.ClassifierCompositeItemWriter.write(ClassifierCompositeItemWriter.java:65)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.writeItems(SimpleChunkProcessor.java:171)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.doWrite(SimpleChunkProcessor.java:150)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.write(SimpleChunkProcessor.java:269)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:194)
    at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:74)
    at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:386)
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:130)
    at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:264)
    at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:76)
    at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:367)
    at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:214)
    at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:143)
    at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:250)
    at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:195)
    at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:135)
    at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:61)
    at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:60)
    at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:144)
    at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:124)
    at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:135)
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:281)
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:120)
    at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:48)
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:114)
person user2228932    schedule 31.03.2013
comment
Каково решение тогда? - person Trinimon; 31.03.2013
comment
привет @ user2228932 я также получаю ту же ошибку .. вы нашли решение для этого? - person Shankar; 10.04.2015
comment
реализовать ItemStream и переопределить метод open - person Harish; 06.06.2016