জাভাতে সীমাবদ্ধ স্ট্রিংগুলিকে বিভক্ত করার দ্রুততম উপায়


10

আমি একটি তুলনাকারী তৈরি করছি যা একটি সীমিত স্ট্রিংয়ের উপর বহু-কলামের বাছাইয়ের ক্ষমতা সরবরাহ করে। আমি বর্তমানে কাঁচা স্ট্রিংকে টোকনে বিভক্ত করার জন্য আমার পছন্দসই পছন্দ হিসাবে স্ট্রিং ক্লাস থেকে বিভাজন পদ্ধতিটি ব্যবহার করছি।

কাঁচা স্ট্রিংকে স্ট্রিং অ্যারে রূপান্তর করার জন্য এটি কি সেরা সম্পাদন পদ্ধতি? আমি কয়েক মিলিয়ন সারি বাছাই করব তাই আমার মনে হয় পদ্ধতির বিষয়টি গুরুত্বপূর্ণ।

এটি দুর্দান্ত চলছে বলে মনে হচ্ছে এবং এটি খুব সহজ, তবে জাভাতে আরও দ্রুত উপায় আছে কিনা তা সম্পর্কে নিশ্চিত ure

সাজানো কীভাবে আমার তুলকটিতে কাজ করে তা এখানে:

public int compare(String a, String b) {

    String[] aValues = a.split(_delimiter, _columnComparators.length);
    String[] bValues = b.split(_delimiter, _columnComparators.length);
    int result = 0;

    for( int index : _sortColumnIndices ) {
        result = _columnComparators[index].compare(aValues[index], bValues[index]);
        if(result != 0){
            break;
        }
    }
    return result;
}

বিভিন্ন পদ্ধতির বেঞ্চমার্ক করার পরে, এটি বিশ্বাস করুন বা না বিশ্বাস করুন, বিভাজনের পদ্ধতিটি জাভার সর্বশেষতম সংস্করণটি ব্যবহার করে দ্রুততম ছিল। আপনি আমার সমাপ্তি তুলকটি এখানে ডাউনলোড করতে পারেন: https://sourceforge.net/projects/multicolumnrowcomparator/


5
আমি উল্লেখ করব যে এই প্রশ্নের উত্তরের প্রকৃতি জেভিএম বাস্তবায়নের উপর নির্ভর করে। স্ট্রিংগুলির আচরণ (ওপেনজেডিকে একটি সাধারণ ব্যাকিং অ্যারে ভাগ করে নেওয়া, তবে ওরাকলজেডিকে নয়) পৃথক। এই পার্থক্যটি আবর্জনা সংগ্রহ এবং মেমরি ফাঁসের পাশাপাশি বিভক্ত স্ট্রিং এবং সাবস্ট্রিংগুলি তৈরিতে উল্লেখযোগ্য প্রভাব ফেলতে পারে। এই অ্যারেগুলি কত বড়? এখন কেমন আছেন? আপনি কি এমন উত্তর বিবেচনা করবেন যা সত্যিকারের জাভা স্ট্রিংয়ের পরিবর্তে নতুন স্ট্রিংিশ ধরণের তৈরি করে?


অ্যারের আকার কলামগুলির সংখ্যার উপর নির্ভর করে তাই এটি পরিবর্তনশীল। এই মাল্টি-কলামের তুলনামূলকটি এরকমভাবে প্যারামিটার হিসাবে পাস করা হয়েছে: এক্সটার্নালসোর্ট.ডরমেশনসোর্টস ফাইলস (ফাইললিস্ট, নতুন ফাইল ("বিগফাইল সিএসভি")), _ কমপারেটর, চারসেট.ডেফল্টচার্টসেট (), মিথ্যা); বহিরাগত সাজানোর রুটিনটি পুরো সারির স্ট্রিংকে সাজিয়ে তুলবে, এটি আসলে তুলনাকারী যা সাজানো কলামগুলির উপর ভিত্তি করে বিভাজন এবং বাছাই করে
কনস্টান্টিন

আমি লুসিনের টোকেনাইজারগুলির দিকে তাকিয়ে বিবেচনা করব। Lucene কেবলমাত্র একটি শক্তিশালী পাঠ্য বিশ্লেষণ গ্রন্থাগার হিসাবে ব্যবহার করা যেতে পারে যা সহজ এবং জটিল উভয় কাজের জন্যই ভাল সম্পাদন করে
ডগ টি।

অ্যাপাচি কমন্স ল্যাং এর বিবেচনা করুন StringUtils.split[PreserveAllTokens](text, delimiter)
মনিকা

উত্তর:


19

আমি এটির জন্য একটি দ্রুত এবং নোংরা মানদণ্ড পরীক্ষা লিখেছি। এটি different টি বিভিন্ন পদ্ধতির তুলনা করে, যার মধ্যে কিছুতে ডেটা বিভক্ত হওয়ার নির্দিষ্ট জ্ঞান প্রয়োজন।

বেসিক সাধারণ উদ্দেশ্যে বিভক্ত করার জন্য, পেয়ারা স্প্লিটার স্ট্রিং # বিভক্ত () এর চেয়ে 3.5x দ্রুত এবং আমি এটি ব্যবহার করার পরামর্শ দিই। স্ট্রিংটোকেনাইজার তার থেকে কিছুটা দ্রুত এবং ইন্ডেক্সঅফের সাথে নিজেকে ভাগ করা আবার দ্বিগুণ দ্রুত।

কোড এবং আরও তথ্যের জন্য দেখুন http://demeranville.com/battle-of-the-tokenizers-delimited-text-parser-performance/


আপনি যে জেডিকে ব্যবহার করছিলেন তা আমি কেবল কৌতূহলবশত ... এবং এটি যদি ১.6 হয় তবে আমি আপনার ফলাফলগুলি পুনরায় পুনরুদ্ধার করতে আগ্রহী 1.. 1.।

1
এটা ছিল 1.6 আমি মনে করি। কোডটি সেখানে JUnit পরীক্ষা হিসাবে রয়েছে যদি আপনি এটি 1.7 এ চালাতে চান। দ্রষ্টব্য স্ট্রিং.স্প্লিট রিজেক্স ম্যাচিং সম্পাদন করে যা সর্বদা একক সংজ্ঞায়িত চরিত্রের বিভাজনের চেয়ে ধীর হয়ে যায়।
টম

1
হ্যাঁ, তবে ১.6 এর জন্য, স্ট্রিংটোকেনাইজার (এবং অনুরূপ) কোডটি একটি স্ট্রিং.সুবস্ট্রিং () কল করে যা একই ব্যাকিং অ্যারে ব্যবহার করে নতুন স্ট্রিংয়ের ও (1) তৈরি করে। ও (এন) এর পরিবর্তে ব্যাকিং অ্যারের প্রয়োজনীয় অংশের একটি অনুলিপি তৈরি করার জন্য এটি 1.7 এ পরিবর্তন করা হয়েছিল। এটি আপনার ফলাফলগুলিতে বিভাজন এবং স্ট্রিংটোকেনাইজারের মধ্যে পার্থক্য কম করার (এক্ষেত্রে সাবস্ট্রিংয়ের আগে ব্যবহৃত স্ট্র্রিংকে ধীরগতিতে) কমিয়ে দেওয়ার একগুণ প্রভাব ফেলতে পারে।

1
অবশ্যই সত্য। জিনিসটি স্ট্রিংটোকেনাইজার যেভাবে কাজ করে তা "একটি নতুন স্ট্রিং তৈরি করতে 3 টি পূর্ণসংখ্যার নিয়োগ করতে" থেকে "একটি নতুন স্ট্রিং তৈরি করতে, ডেটার একটি অ্যারে অনুলিপি করুন" যা সেই অংশটি কত দ্রুত পরিবর্তন করবে। বিভিন্ন পদ্ধতির মধ্যে পার্থক্য এখন কম হতে পারে এবং জাভা ১.7 এর সাথে ফলোআপ করা আকর্ষণীয় হবে (যদি এটি আকর্ষণীয় ছাড়া অন্য কোনও কারণে না হয়)।

1
নিবন্ধের জন্য ধন্যবাদ! খুব দরকারী এবং বিভিন্ন পদ্ধতির মানদণ্ডে ব্যবহার করবে।
কনস্টান্টিন

5

@ টম যেমন লিখেছেন, তত্ক্ষণাত্ একটি সূচকফুল ধরণের পদ্ধতির চেয়ে দ্রুত হয় String.split(), যেহেতু পরেরটি নিয়মিত প্রকাশের সাথে সম্পর্কিত হয় এবং তাদের জন্য অতিরিক্ত অতিরিক্ত ওভারহেড থাকে।

তবে, একটি অ্যালগরিদম পরিবর্তন যা আপনাকে একটি সুপার স্পিডআপ দিতে পারে। এই তুলনাকারীটি আপনার ~ 100,000 স্ট্রিংগুলি বাছাই করতে ব্যবহৃত হচ্ছে ধরে নেওয়া, এটি লিখবেন না Comparator<String>। কারণ, আপনার বাছাইয়ের সময় একই স্ট্রিংটিকে সম্ভবত একাধিকবার তুলনা করা হবে, সুতরাং আপনি এটিকে একাধিক বার ভাগ করবেন ইত্যাদি ...

সমস্ত স্ট্রিংগুলি একবার স্ট্রিং [] এর মধ্যে বিভক্ত করুন এবং স্ট্রিংটি [] Comparator<String[]>সর্ট করুন। তারপরে, শেষে, আপনি তাদের একত্রিত করতে পারেন।

বিকল্পভাবে, আপনি স্ট্রিং -> স্ট্রিং [] বা এর বিপরীতে ক্যাশে করতে একটি মানচিত্রও ব্যবহার করতে পারেন। উদাহরণস্বরূপ (স্কেচি) এছাড়াও নোট করুন, আপনি গতির জন্য মেমরি ট্রেড করছেন, আশা করি আপনার কাছে লোটাস র্যাম রয়েছে

HashMap<String, String[]> cache = new HashMap();

int compare(String s1, String s2) {
   String[] cached1 = cache.get(s1);
   if (cached1  == null) {
      cached1 = mySuperSplitter(s1):
      cache.put(s1, cached1);
   }
   String[] cached2 = cache.get(s2);
   if (cached2  == null) {
      cached2 = mySuperSplitter(s2):
      cache.put(s2, cached2);
   }

   return compareAsArrays(cached1, cached2);  // real comparison done here
}

এটি একটি ভালো দিক.
টম

এটির জন্য এখানে বাহ্যিক বাছাই কোডের সংশোধন করা দরকার যা এখানে পাওয়া যাবে: code.google.com/p/externalsortinginjava
কনস্টান্টিন

1
সম্ভবত মানচিত্রটি ব্যবহার করা সবচেয়ে সহজ। সম্পাদনা দেখুন।
ব্যবহারকারী949300

প্রদত্ত যে এটি একটি বাহ্যিক সাজানোর ইঞ্জিনের অংশ (সম্ভবত উপলব্ধ মেমরির তুলনায় অনেক বেশি ডেটা মোকাবেলা করতে), আমি সত্যিই একটি দক্ষ "স্প্লিটার" এর পরে যাচ্ছিলাম (হ্যাঁ, বার বার একই স্ট্রিংকে বিভক্ত করা ব্যর্থ, সুতরাং আমার যত তাড়াতাড়ি সম্ভব এটি করার জন্য আসল প্রয়োজন)
কনস্টান্টিন

এক্সটার্ন্যান্টসোর্ট কোড সংক্ষেপে ব্রাউজ করে, দেখে মনে হচ্ছে আপনি যদি প্রতিটি sortAndSave()কলের শেষে (বা শুরু) আপনার ক্যাশে সাফ করে থাকেন তবে বিশাল ক্যাশের কারণে আপনার স্মৃতিশক্তি চলে না। আইএমও, কোডটিতে কয়েকটি অতিরিক্ত হুক থাকা উচিত যেমন গুলি ছোঁড়ার ঘটনা বা কল-ডু-কিছুই সুরক্ষিত পদ্ধতিগুলি নয় যা আপনার মতো ব্যবহারকারীরা ওভাররাইড করতে পারে। (এছাড়া, এটিও সব স্ট্যাটিক পদ্ধতি যাতে তারা করতে পারেন হওয়া উচিত না এই) আপনি লেখক সঙ্গে যোগাযোগ করুন এবং একটি অনুরোধ দায়ের করতে পারেন।
ব্যবহারকারী949300

2

এই মানদণ্ড অনুসারে , স্ট্রিংটোকেনাইজার বিভক্ত স্ট্রিংগুলির জন্য দ্রুত তবে এটি কোনও অ্যারে ফিরিয়ে দেয় না যা এটি কম সুবিধাজনক করে তোলে।

আপনার যদি কয়েক মিলিয়ন সারি বাছাই করতে হয় তবে আমি একটি আরডিবিএমএস ব্যবহার করার পরামর্শ দেব।


3
এটি জেডিকে ১. under এর অধীনে ছিল - স্ট্রিংয়ের জিনিসগুলি মূলত 1.7-এ আলাদা - java-performance.info/changes-to-string-java-1-7-0_06 দেখুন (বিশেষত, স্ট্রাস্টিং তৈরি করা এখন আর (1) নয়) বরং ও (এন))। লিঙ্কটি নোট করে যে ১.6 প্যাটার্ন.স্প্লিট স্ট্রিং.সুবস্ট্রিং () এর চেয়ে পৃথক স্ট্রিং তৈরি ব্যবহার করেছে - স্ট্রিংটোকেনাইজার.সেক্সটটোকেন () এবং এটিতে প্যাকেজ ব্যক্তিগত কন্সট্রাক্টর ব্যবহার করার জন্য উপরের মন্তব্যে লিঙ্কযুক্ত কোডটি দেখুন।

1

বৃহত (1GB +) ট্যাব-সীমিত ফাইলগুলি পার্স করার জন্য আমি এই পদ্ধতিটি ব্যবহার করি। এটির তুলনায় এটির তুলনায় অনেক কম ওভারহেড রয়েছে String.split()তবে charডিলিমিটার হিসাবে সীমাবদ্ধ। কারও কাছে যদি দ্রুত পদ্ধতি থাকে তবে আমি এটি দেখতে চাই। এটিও করা যেতে পারে CharSequenceএবং CharSequence.subSequence, তবে এর বাস্তবায়ন প্রয়োজন CharSequence.indexOf(char)( String.indexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex)আগ্রহী হলে প্যাকেজ পদ্ধতিটি দেখুন )।

public static String[] split(final String line, final char delimiter)
{
    CharSequence[] temp = new CharSequence[(line.length() / 2) + 1];
    int wordCount = 0;
    int i = 0;
    int j = line.indexOf(delimiter, 0); // first substring

    while (j >= 0)
    {
        temp[wordCount++] = line.substring(i, j);
        i = j + 1;
        j = line.indexOf(delimiter, i); // rest of substrings
    }

    temp[wordCount++] = line.substring(i); // last substring

    String[] result = new String[wordCount];
    System.arraycopy(temp, 0, result, 0, wordCount);

    return result;
}

আপনি কি এই বনাম স্ট্রিং.স্প্লিট () কে বেঞ্চমার্ক করেছেন? যদি তা হয় তবে এর তুলনা কীভাবে হয়?
জে এলস্টন

@ জাএলস্টন ৯০০ এমবি ফাইলে এটি বিভাজনের সময়টি 7..7 সেকেন্ড থেকে .2.২ সেকেন্ডে কমিয়েছে, তাই প্রায় ২০% দ্রুত faster এটি এখনও আমার ভাসমান-পয়েন্ট ম্যাট্রিক্স পার্সিংয়ের ধীরতম অংশ। আমি অনুমান করছি যে বাকি সময়টির বেশিরভাগ অংশ অ্যারে বরাদ্দ। পদ্ধতিতে অফসেট সহ টোকেনাইজার-ভিত্তিক পদ্ধতির সাহায্যে ম্যাট্রিক্স বরাদ্দটি কাটা সম্ভব হতে পারে - যা কোডের উপরে বর্ণিত পদ্ধতিটির মতো দেখতে আরও বেশি দেখাবে।
vallismortis
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.