语境
我们有一个批处理作业,可将本地化的国家名称(即国家名称翻译为不同语言)从外部复制到我们的数据库中。这个想法是在1个块中处理单个国家/地区的所有本地化的国家名称(即第一个块-
安道尔的所有翻译,下一个块-
阿联酋的所有翻译,等等)。我们使用JdbcCursorItemReader
读取外部数据和一些oracle分析功能来提供该国家/地区可用的翻译总数:
select country_code, language_code, localized_name, COUNT(1) OVER(PARTITION BY c_lng.country_code) as lng_count
from EXT_COUNTRY_LNG c_lng
order by c_lng.countty_code, c_lng.language_code
问题
因此,按块分割此输入看起来很简单:在读取了其中指定的确切行数后停止块,lng_count
然后从下一个读取的行开始一个新的行,但实际上似乎并不那么简单:(
首先要尝试的是自定义完成政策。但是问题是,它无权访问由ItemReader
读者阅读的最后一项-
您应该将其明确地放在阅读器中的上下文中,并将其返回到策略中。不喜欢它,因为它需要其他阅读器修改/添加阅读器侦听器。此外,我不喜欢将同一项目来回序列化/反序列化。而且我觉得JobContext
/
StepContext
不是存放此类数据的好地方。
还有RepeatContext
一个看起来更适合存放此类数据的地方,但我无法 轻松 访问它……
所以最后我们得到这样的解决方案:
@Bean(name = "localizedCountryNamesStep")
@JobScope
public Step insertCountryStep(
final StepBuilderFactory stepBuilderFactory,
final MasterdataCountryNameReader countryNameReader,
final MasterdataCountryNameProcessor countryNameProcessor,
final MasterdataCountryNameWriter writer) {
/* Use the same fixed-commit policy, but update it's chunk size dynamically */
final SimpleCompletionPolicy policy = new SimpleCompletionPolicy();
return stepBuilderFactory.get("localizedCountryNamesStep")
.<ExtCountryLng, LocalizedCountryName> chunk(policy)
.reader(countryNameReader)
.listener(new ItemReadListener<ExtCountryLng>() {
@Override
public void beforeRead() {
// do nothing
}
@Override
public void afterRead(final ExtCountryLng item) {
/* Update the cunk size after every read: consequent reads
inside the same country = same chunk do nothing since lngCount is always the same there */
policy.setChunkSize(item.getLngCount());
}
@Override
public void onReadError(final Exception ex) {
// do nothing
}
})
.processor(countryNameProcessor)
.writer(writer)
.faultTolerant()
.skip(RuntimeException.class)
.skipLimit(Integer.MAX_VALUE) // Batch does not support unlimited skip
.retryLimit(0) // this solution disables only retry, but not recover
.build();
}
它可以正常工作,需要最少的代码更改,但是对我来说还是有点难看。所以我想知道,当所有必需的信息已经在时可用,是否有另一种优雅的方法可以在Spring
Batch中执行动态块大小ItemReader
?
最简单的方法是按国家划分您的步骤。这样,每个国家都可以迈出自己的一步,您还可以跨国家穿梭,以提高绩效。
如果需要一个读者,则可以包装委托PeekableItemReader
并扩展SimpleCompletionPolicy
以实现您的目标。
public class CountryPeekingCompletionPolicyReader extends SimpleCompletionPolicy implements ItemReader<CountrySpecificItem> {
private PeekableItemReader<? extends CountrySpecificItem> delegate;
private CountrySpecificItem currentReadItem = null;
@Override
public CountrySpecificItem read() throws UnexpectedInputException, ParseException, NonTransientResourceException, Exception {
currentReadItem = delegate.read();
return currentReadItem;
}
@Override
public RepeatContext start(final RepeatContext context) {
return new ComparisonPolicyTerminationContext(context);
}
protected class ComparisonPolicyTerminationContext extends SimpleTerminationContext {
public ComparisonPolicyTerminationContext(final RepeatContext context) {
super(context);
}
@Override
public boolean isComplete() {
final CountrySpecificItem nextReadItem = delegate.peek();
// logic to check if same country
if (currentReadItem.isSameCountry(nextReadItem)) {
return false;
}
return true;
}
}
}
然后根据您的上下文定义:
<batch:tasklet>
<batch:chunk chunk-completion-policy="countrySpecificCompletionPolicy" reader="countrySpecificCompletionPolicy" writer="someWriter" />
</batch:tasklet>
<bean id="countrySpecificCompletionPolicy" class="CountryPeekingCompletionPolicyReader">
<property name="delegate" ref="peekableReader" />
</bean>
<bean id="peekableReader" class="YourPeekableItemReader" />
编辑: 仔细考虑您的问题,分区是最干净的方法。使用分区步骤,将从步骤执行上下文向每个ItemReader(确保scope="step"
)传递一个countryName
。是的,您需要一个自定义Partitioner
类来构建执行上下文图(每个国家/地区一个条目)和一个硬编码的提交间隔,该间隔足够大以容纳最大的工作单元,但是此后一切都非常简单,并且每个从属步骤仅是一个单独的步骤,对于可能遇到问题的任何国家,重新启动应该是一件轻而易举的事。
上下文 我们有一个批处理作业,可以将本地化的国家名称(即将国家名称翻译成不同的语言)从外部复制到我们的数据库中。其想法是将单个国家的所有本地化国家名称处理为一个区块(即第一区块-安道尔的所有翻译,下一区块-阿联酋的所有翻译,等等)。我们使用读取外部数据,一些oracle分析函数提供国家可用的翻译总数:比如 问题 因此,按块剪切这个输入看起来很简单:当您读取了中指定的确切行数时,停止块,并用下一个读
嗨,我有一个骆驼路线,它分割一条传入的消息,然后我想聚合这条消息,但我不知道会分割多少条消息。 我使用了以下方法: 这不起作用,而且挂起了……不过,如果我将完成大小设置为一个数值,它就起作用了。 有人知道如何动态聚合,并等待完成。顺便说一下,标题是在分割之前设置的。
问题内容: 如何通过“静态”方面和“动态”方面自定义的完成?静态方面是因为某些条目是已知的,并在构造时使用添加到了组合框文本中。动态方面是因为我还需要通过一些回调函数来完成,也就是说,一旦键入了几个字符,即在创建窗口小部件之后 动态地 完成。 我的应用程序使用的是Boehm的GC(当然不包括GTK对象),例如Guile或SCM或Bigloo。它可以看作是一种实验 性的持久性 动态类型的编程语言实现
我想创建基于自动完成输入的动态谷歌地图。我把代码写成:- 地图没出现。请解决它..我通过参考https://youtu.be/2n_r0ndekgc上的视频编写了代码
我想在表单中使用jQuery.AutoComplete.js插件进行输入。我想在客户端进行搜索,不能使用Ajax。但我不想在数组中使用一些简单的基于“包含”的搜索算法。我要做的是用javascript编写一个自定义搜索函数,对结果进行搜索和排序。这可能吗?怎么可能? 谢谢你抽出时间。
我试图创建自己的自定义angular material组件,该组件能够使用控件。 除此之外,我希望该控件使用指令。 我的目的只是创建一个更好看的组件,该组件包含一个集成的clear按钮和自定义css箭头,如下图所示。我使用标准组件成功地获得了它,并添加了我想要的内容,但现在我想将它导出到泛型组件中。 null 即使正确选择了值,我的窗体也无效。 选择某个选项后,占位符自身设置不正确。 自动完成筛选