Ошибка: java.lang.IllegalArgumentException: метод сравнения нарушает свой общий контракт даже при использовании обходного пути

Я уже потратил два дня, чтобы устранить эту ошибку, даже я пробовал обходной путь, который предлагается в нескольких сообщениях stackoverflow «-Djava.util.Arrays.useLegacyMergeSort=true», но он также не работает.

это подробности моей команды и возвращаемой ошибки:

Команда:

hadoop jar CloudBrush.jar -Djava.awt.headless=true -Djava.util.Arrays.useLegacyMergeSort=true -reads /Ec10k -asm Ec10k_Brush -k 21 -readlen 36

Ошибка:

    Error: java.lang.IllegalArgumentException: Comparison method violates its general contract!
    at java.util.TimSort.mergeHi(TimSort.java:895)
    at java.util.TimSort.mergeAt(TimSort.java:512)
    at java.util.TimSort.mergeCollapse(TimSort.java:437)
    at java.util.TimSort.sort(TimSort.java:241)
    at java.util.Arrays.sort(Arrays.java:1512)
    at java.util.ArrayList.sort(ArrayList.java:1454)
    at java.util.Collections.sort(Collections.java:175)
    at Brush.VerifyOverlap$VerifyOverlapReducer.reduce(VerifyOverlap.java:252)
    at Brush.VerifyOverlap$VerifyOverlapReducer.reduce(VerifyOverlap.java:1)
    at org.apache.hadoop.mapred.ReduceTask.runOldReducer(ReduceTask.java:444)
    at org.apache.hadoop.mapred.ReduceTask.run(ReduceTask.java:392)
    at org.apache.hadoop.mapred.YarnChild$2.run(YarnChild.java:163)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAs(Subject.java:422)
    at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1628)
    at org.apache.hadoop.mapred.YarnChild.main(YarnChild.java:158)

Exception in thread "main" java.io.IOException: Job failed!
    at org.apache.hadoop.mapred.JobClient.runJob(JobClient.java:836)
    at Brush.VerifyOverlap.run(VerifyOverlap.java:381)
    at Brush.BrushAssembler.buildOverlap(BrushAssembler.java:326)
    at Brush.BrushAssembler.run(BrushAssembler.java:838)
    at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:70)
    at Brush.BrushAssembler.main(BrushAssembler.java:913)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.apache.hadoop.util.RunJar.run(RunJar.java:221)
    at org.apache.hadoop.util.RunJar.main(RunJar.java:136)

Это Comparator:

    class OvelapSizeComparator implements Comparator {
        public int compare(Object element1, Object element2) {
            OverlapInfo obj1 = (OverlapInfo) element1;
            OverlapInfo obj2 = (OverlapInfo) element2;
            if ((int)(obj1.overlap_size - obj2.overlap_size) >= 0) {
                return -1;
            } else {
                return 1;
            }
        }
    }

person hemant gupta    schedule 13.07.2015    source источник
comment
Вместо того, чтобы пытаться найти обходной путь, попробуйте исправить неверный код компаратора. Мы не сможем помочь вам с этим, если вы не опубликуете его.   -  person JB Nizet    schedule 13.07.2015
comment
Нужно добавить свой код, чтобы кто-то мог помочь   -  person chintan thakar    schedule 13.07.2015
comment
Обходной путь работает только в том случае, если ваша функция сравнения правильно реализует условия больше и меньше, а не исправляет ошибочную функцию сравнения. Не видя кода, мы не можем это проверить.   -  person Bernhard Barker    schedule 13.07.2015
comment
Вот ссылка на полный репозиторий github для пакета: github. com/ice91/CloudBrush/blob/master/src/Brush/ Файл VerifyOverlap.java, содержащий код, который вызывает эту ошибку. Это инструмент на основе Hadoop для сборки геномных данных.   -  person hemant gupta    schedule 13.07.2015


Ответы (3)


Настоящая проблема заключается в том, что ваш OvelapSizeComparator [sic] неисправен. Если значения overlap_size двух объектов равны, он возвращает -1 вместо того, чтобы возвращать 0. И если они не равны, возвращает значение с неверным знаком.

Чтобы исправить это, замените это:

if ((int)(obj1.overlap_size - obj2.overlap_size) >= 0) {
   return -1;
} else {
   return 1;
}

...с этим:

return obj1.overlap_size - obj2.overlap_size;
person Kevin Krumwiede    schedule 31.07.2015
comment
@hemant gupta, пожалуйста, исправьте свой код и примите этот ответ. Сообщение об ошибке говорит само за себя, и ИМХО является довольно серьезным указателем на серьезную проблему в вашем коде. Вам повезло, что сообщение об ошибке четко указывает на основную причину вашей проблемы. - person Olaf Kock; 22.12.2015

Вы можете воспроизвести эту ошибку, запустив основной метод в коде Test.java на JVM 7 или более поздних версиях. Подводя итог тому, что делает этот код. Этот код пытается отсортировать объекты из 40 человек с помощью метода сравнения, который не содержит транзитивного свойства.

//Person.java

открытый класс Person реализует Comparable{

public String name;
public int age ;
public int salary;

@Override
public int compareTo(Person o) {
    if(o instanceof Person){
        int ret=0;
        if(age == 25 && ((Person)o).age ==27) ret = 1;
        else if(age == 27 && ((Person)o).age ==29) ret = 1;
        else if(age == 25 && ((Person)o).age ==29) ret = -1;
        else{
                if( age < ((Person)o).age) ret = -1;
                if(age > ((Person)o).age) ret = 1;
                if(salary < ((Person)o).salary) ret = -1;
                if(salary > ((Person)o).salary) ret = 1;           
        }
        return ret; 

    }
    return 0;
}

@Override
public String toString(){
 return "name="+name+":age="+age+";";     
}

}

//Тест.java

импортировать java.util.Arrays;

открытый класс Тест {

public static void main(String args[]) {
    Test t = new Test();
    t.sortPersons(args);        
}

public void sortPersons(String args[]) {        

    Person p1 = new Person();
    p1.age = 25;
    p1.name = "ABC";

    Person p2 = new Person();
    p2.age = 29;
    p2.name = "ABZ";

    Person p3 = new Person();
    p3.age = 27;
    p3.name = "AZ";

    Person p4 = new Person();
    p4.age = 27;
    p4.name = "AZ";

    Person p5 = new Person();
    //p5.age = 22;
    //p5.name="ZZ";

    Person[] p = new Person[40];

    p[0] = p2;
    p[1] = p3;
    p[2] = p4;
    p[3] = p1;
    p[4] = p5;
    for (int i = 1; i < 8; i++) {
        p[i * 5] = p[0];
        p[i * 5 + 1] = p[1];
        p[i * 5 + 2] = p[2];
        p[i * 5 + 3] = p[3];
        p[i * 5 + 4] = p[4];
    }

    System.out.println("\nSortingInput\n");           
    Arrays.sort(p);       
    System.out.println("\nSorting complete\n");
}

}

person Revanth Segu    schedule 31.07.2015

Я исправил ошибку. Я думал, что это проблема с Hadoop, но я ошибался. Это проблема с версией Java. Мы также обновили версию Java вместе с Hadoop. Метод Arrays.sort() для java 7 и java 8 использует TimSort, если количество сортируемых элементов превышает 32. А сортировка Tim применяет строгое транзитивное свойство при сравнении.

Если ((compare(x, y)>0) && (compare(y, z)>0)) то compare(x, z) должно быть больше 0. В противном случае "java.lang.IllegalArgumentException: метод сравнения нарушает его общие Контракт" выдает ошибку.

Либо вы должны изменить свой метод сравнения, чтобы он соответствовал транзитивному свойству, либо использовать сортировку более старой версии, установив для «java.util.Arrays.useLegacyMergeSort» значение true для «Map Task Java Opts Base» или «Reduce Task Java Opts Base», а затем должен применяться ко всем запущенным JVM для отображения или уменьшения.

Для 2.6.0-cdh5.4.2 Haddop вы можете добавить этот параметр в задачу сопоставления, добавив

-D mapreduce.map.java.opts= "-Djava.util.Arrays.useLegacyMergeSort=true"
-D mapreduce.reduce.java.opts= "-Djava.util.Arrays.useLegacyMergeSort=true"

или через код

job.getConfiguration().set("mapreduce.map.java.opts","-Djava.util.Arrays.useLegacyMergeSort=true");

job.getConfiguration().set("mapreduce.reduce.java.opts","-Djava.util.Arrays.useLegacyMergeSort=true");

person Revanth Segu    schedule 31.07.2015
comment
Это не проблема с версией Java. Более новая версия Java просто выявляет проблему в вашем коде. - person Kevin Krumwiede; 01.08.2015