আমি Stream
অজানা সংখ্যার দূরবর্তীভাবে সঞ্চিত জেএসওএন ফাইলগুলির একটি ভিন্ন ভিন্ন সেটগুলির সমান্তরাল প্রক্রিয়াকরণের জন্য একটি ব্যবহার করতে চাই (ফাইলগুলির সংখ্যাটি সামনে জানা যায় না)। ফাইলগুলি আকারে বিভিন্ন আকারে পরিবর্তিত হতে পারে, প্রতি ফাইল 1 জেএসওএন রেকর্ড থেকে অন্য কয়েকটি ফাইলে 100,000 রেকর্ড পর্যন্ত। এই ক্ষেত্রে একটি JSON রেকর্ডের অর্থ ফাইলটিতে একটি লাইন হিসাবে প্রতিনিধিত্ব করা একটি স্ব-অন্তর্ভুক্ত JSON অবজেক্ট।
আমি সত্যিই এর জন্য স্ট্রিম ব্যবহার করতে চাই এবং তাই আমি এটি প্রয়োগ করেছি Spliterator
:
public abstract class JsonStreamSpliterator<METADATA, RECORD> extends AbstractSpliterator<RECORD> {
abstract protected JsonStreamSupport<METADATA> openInputStream(String path);
abstract protected RECORD parse(METADATA metadata, Map<String, Object> json);
private static final int ADDITIONAL_CHARACTERISTICS = Spliterator.IMMUTABLE | Spliterator.DISTINCT | Spliterator.NONNULL;
private static final int MAX_BUFFER = 100;
private final Iterator<String> paths;
private JsonStreamSupport<METADATA> reader = null;
public JsonStreamSpliterator(Iterator<String> paths) {
this(Long.MAX_VALUE, ADDITIONAL_CHARACTERISTICS, paths);
}
private JsonStreamSpliterator(long est, int additionalCharacteristics, Iterator<String> paths) {
super(est, additionalCharacteristics);
this.paths = paths;
}
private JsonStreamSpliterator(long est, int additionalCharacteristics, Iterator<String> paths, String nextPath) {
this(est, additionalCharacteristics, paths);
open(nextPath);
}
@Override
public boolean tryAdvance(Consumer<? super RECORD> action) {
if(reader == null) {
String path = takeNextPath();
if(path != null) {
open(path);
}
else {
return false;
}
}
Map<String, Object> json = reader.readJsonLine();
if(json != null) {
RECORD item = parse(reader.getMetadata(), json);
action.accept(item);
return true;
}
else {
reader.close();
reader = null;
return tryAdvance(action);
}
}
private void open(String path) {
reader = openInputStream(path);
}
private String takeNextPath() {
synchronized(paths) {
if(paths.hasNext()) {
return paths.next();
}
}
return null;
}
@Override
public Spliterator<RECORD> trySplit() {
String nextPath = takeNextPath();
if(nextPath != null) {
return new JsonStreamSpliterator<METADATA,RECORD>(Long.MAX_VALUE, ADDITIONAL_CHARACTERISTICS, paths, nextPath) {
@Override
protected JsonStreamSupport<METADATA> openInputStream(String path) {
return JsonStreamSpliterator.this.openInputStream(path);
}
@Override
protected RECORD parse(METADATA metaData, Map<String,Object> json) {
return JsonStreamSpliterator.this.parse(metaData, json);
}
};
}
else {
List<RECORD> records = new ArrayList<RECORD>();
while(tryAdvance(records::add) && records.size() < MAX_BUFFER) {
// loop
}
if(records.size() != 0) {
return records.spliterator();
}
else {
return null;
}
}
}
}
আমার যে সমস্যাটি হচ্ছে তা হ'ল প্রথমদিকে যখন স্ট্রিমটি সুন্দরভাবে সমান্তরাল হয়, শেষ পর্যন্ত বৃহত্তম ফাইলটি একক থ্রেডে প্রসেসিংয়ের বাকি থাকে। আমি বিশ্বাস করি যে প্রক্সিমাল কারণটি ভালভাবে নথিভুক্ত হয়েছে: স্প্লিটেটরটি "ভারসাম্যহীন"।
আরও দৃ concrete়তার সাথে দেখা যায় যে trySplit
পদ্ধতিটি একটি নির্দিষ্ট পয়েন্টের পরে Stream.forEach
লাইফসাইকেলে বলা হয় না , সুতরাং শেষে ছোট ছোট ব্যাচগুলি বিতরণের অতিরিক্ত যুক্তি trySplit
খুব কমই সম্পাদিত হয়।
লক্ষ্য করুন যে কীভাবে সমস্ত স্প্লিটেটর ট্রাইস্প্লিট থেকে একই পুনরায় ভাগ করে নিয়েছে paths
। আমি ভেবেছিলাম এটি সমস্ত স্প্লিটেটরেটরগুলির মধ্যে কাজ ভারসাম্য করার সত্যিই চতুর উপায়, তবে এটি সম্পূর্ণ সমান্তরালতা অর্জন করার পক্ষে পর্যাপ্ত হয়নি।
আমি প্রথমে ফাইলগুলি জুড়ে সমান্তরাল প্রক্রিয়াজাতকরণটি চাই এবং তারপরে যখন কয়েকটি বড় ফাইল এখনও বিভক্ত হয়, তখন আমি বাকী ফাইলগুলির অংশগুলিতে সমান্তরাল করতে চাই। এটি ছিল else
শেষে ব্লকের অভিপ্রায় trySplit
।
এই সমস্যাটি ঘিরে কি কোনও সহজ / সরল / প্রচলিত উপায় আছে?
Long.MAX_VALUE
ফলে অতিরিক্ত এবং অপ্রয়োজনীয় বিভাজন ঘটে, অন্যদিকে অন্য যে কোনও অনুমানের Long.MAX_VALUE
কারণে আরও বিভাজন বন্ধ হয়ে যায় এবং সমান্তরালতা নিহত হয়। সঠিক অনুমানের মিশ্রণ ফিরিয়ে দেওয়া কোনও বুদ্ধিমান অপ্টিমাইজেশনের দিকে নিয়ে যায় বলে মনে হয় না।
AbstractSpliterator
তবে ওভাররাইড করছেন trySplit()
যা কোনও কিছু বাদে কোনও খারাপ কম্বো Long.MAX_VALUE
, কারণ আপনি আকারের অনুমানটি মানিয়ে নিচ্ছেন না trySplit()
। তারপরে trySplit()
, আকারের অনুমানটি বিভক্ত হয়ে যাওয়া উপাদানগুলির সংখ্যা দ্বারা হ্রাস করা উচিত।