在 Spring Batch 中压平列表列表的最佳方法是什么?
What is the best way to flatten a list of lists in Spring Batch?
在 Spring 批处理中,处理器从一种输入类型映射到一种输出类型。但是我需要从一个 I
生成一个输出类型列表 (List<O>
)。
处理器可以 return List<O>
就好了,但假设我想在后续处理器中将此列表的元素作为单独的元素来处理。我应该先将它们写入数据库吗?事实上,我需要对 List<O>
的每个成员进行远程服务,因此我不想将它们写在任何地方,直到可以处理列表中的各个对象。
这与我的 有关,我在其中被告知 @JobScope
和内存中的对象在步骤之间的传输是 90% 的代码味道。我很好奇我是否在这里缺少一个特殊的 Spring 批处理模式,用于展平生成的列表列表,这与在处理之前将半生不熟的对象写入数据库、缓存或平面文件不同。
但最终我希望作者使用一大块 O
而不是一大块 List<O>
。那么推荐的方法是什么?到目前为止,我想出了以下用作 @JobScope
bean 的方法:
public class FlatMapPipe<T> implements ItemWriter<List<T>>, ItemReader<T> {
private LinkedList<List<T>> lists = new LinkedList<List<T>>();
/**
* Pages through the internal linked list to find the next item
* @return next item in the current list or the first item in the next list or null
* @throws Exception
* @throws UnexpectedInputException
* @throws ParseException
* @throws NonTransientResourceException
*/
@Override
public T read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
if (lists.size() == 0) {
return null;
}
List<T> list = lists.get(0);
if (list.isEmpty()) {
lists.remove();
return read();
} else {
return list.remove(0);
}
}
/**
* Appends a list to the linked list of lists of written Items
* @param list
* @throws Exception
*/
@Override
public void write(List<? extends List<T>> list) throws Exception {
list.forEach((it) -> lists.add(new ArrayList<>(it)));
}
}
The processor can return the List just fine, but supposing I want to work with the elements of this list as individuals in subsequent processors. Am I expected to write them to the database first?
不用先写入数据库,效率低下。封装是您的朋友,您可以将处理器的结果包装在聚合类型中,该聚合类型可以传递给链中的后续处理器(例如使用复合处理器)。然后项目编写器负责执行平面映射操作,以便在写入之前从聚合类型中解开完全处理的项目。
另一种技术是使用两个并发步骤和一个暂存区(您将在其中展平项目),如 issue #2044. I implemented a PoC here 中所述,并将阻塞队列作为暂存区。在您的情况下,第一步将处理项目并将结果写入队列,第二步可以从队列中读取(平面)项目,根据需要丰富它们并在适当的地方写入它们。
在 Spring 批处理中,处理器从一种输入类型映射到一种输出类型。但是我需要从一个 I
生成一个输出类型列表 (List<O>
)。
处理器可以 return List<O>
就好了,但假设我想在后续处理器中将此列表的元素作为单独的元素来处理。我应该先将它们写入数据库吗?事实上,我需要对 List<O>
的每个成员进行远程服务,因此我不想将它们写在任何地方,直到可以处理列表中的各个对象。
这与我的 @JobScope
和内存中的对象在步骤之间的传输是 90% 的代码味道。我很好奇我是否在这里缺少一个特殊的 Spring 批处理模式,用于展平生成的列表列表,这与在处理之前将半生不熟的对象写入数据库、缓存或平面文件不同。
但最终我希望作者使用一大块 O
而不是一大块 List<O>
。那么推荐的方法是什么?到目前为止,我想出了以下用作 @JobScope
bean 的方法:
public class FlatMapPipe<T> implements ItemWriter<List<T>>, ItemReader<T> {
private LinkedList<List<T>> lists = new LinkedList<List<T>>();
/**
* Pages through the internal linked list to find the next item
* @return next item in the current list or the first item in the next list or null
* @throws Exception
* @throws UnexpectedInputException
* @throws ParseException
* @throws NonTransientResourceException
*/
@Override
public T read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
if (lists.size() == 0) {
return null;
}
List<T> list = lists.get(0);
if (list.isEmpty()) {
lists.remove();
return read();
} else {
return list.remove(0);
}
}
/**
* Appends a list to the linked list of lists of written Items
* @param list
* @throws Exception
*/
@Override
public void write(List<? extends List<T>> list) throws Exception {
list.forEach((it) -> lists.add(new ArrayList<>(it)));
}
}
The processor can return the List just fine, but supposing I want to work with the elements of this list as individuals in subsequent processors. Am I expected to write them to the database first?
不用先写入数据库,效率低下。封装是您的朋友,您可以将处理器的结果包装在聚合类型中,该聚合类型可以传递给链中的后续处理器(例如使用复合处理器)。然后项目编写器负责执行平面映射操作,以便在写入之前从聚合类型中解开完全处理的项目。
另一种技术是使用两个并发步骤和一个暂存区(您将在其中展平项目),如 issue #2044. I implemented a PoC here 中所述,并将阻塞队列作为暂存区。在您的情况下,第一步将处理项目并将结果写入队列,第二步可以从队列中读取(平面)项目,根据需要丰富它们并在适当的地方写入它们。