Почему Lucene вызывает OOM при индексации больших файлов? - PullRequest
5 голосов
/ 01 сентября 2009

Я работаю с Lucene 2.4.0 и JVM (JDK 1.6.0_07). Я постоянно получаю OutOfMemoryError: Java heap space при попытке индексировать большие текстовые файлы.

Пример 1. При индексации текстового файла объемом 5 МБ заканчивается память с максимальным объемом 64 МБ. размер кучи. Поэтому я увеличил макс. Размер кучи до 512 МБ. Это работало для текстового файла 5 МБ, но Lucene все еще использовал 84 МБ кучи для этого. Почему так много?

Класс FreqProxTermsWriterPerField, по-видимому, является самым большим потребителем памяти, согласно JConsole и плагину TPTP Memory Profiling для Eclipse Ganymede.

Пример 2. При индексации текстового файла объемом 62 МБ заканчивается память с максимальным объемом 512 МБ. размер кучи. Увеличение макс. Размер кучи до 1024 МБ работает, но Lucene использует 826 МБ пространства кучи при выполнении этого. Похоже, слишком много памяти используется для этого. Я уверен, что большие файлы вызовут ошибку, поскольку она кажется корреляционной.

Я на платформе Windows XP SP2 с 2 ГБ ОЗУ. Так что же является лучшим методом для индексации больших файлов? Вот фрагмент кода, который я использую:

// Index the content of a text file.
private Boolean saveTXTFile(File textFile, Document textDocument) throws MyException {           

        try {             

              Boolean isFile = textFile.isFile();
              Boolean hasTextExtension = textFile.getName().endsWith(".txt");

              if (isFile && hasTextExtension) {

                    System.out.println("File " + textFile.getCanonicalPath() + " is being indexed");
                    Reader textFileReader = new FileReader(textFile);
                    if (textDocument == null)
                          textDocument = new Document();
                    textDocument.add(new Field("content", textFileReader));
                    indexWriter.addDocument(textDocument);   // BREAKS HERE!!!!
              }                    
        } catch (FileNotFoundException fnfe) {
              System.out.println(fnfe.getMessage());
              return false;
        } catch (CorruptIndexException cie) {
              throw new MyException("The index has become corrupt.");
        } catch (IOException ioe) {
              System.out.println(ioe.getMessage());
              return false;
        }                    
        return true;
  }

Ответы [ 5 ]

4 голосов
/ 04 сентября 2009

В ответ в качестве комментария к Гэндальф

Я вижу, вы устанавливаете setMergeFactor на 1000

API говорит

setMergeFactor

public void setMergeFactor (int MergeFactor)

Определяет как часто Сегментные индексы объединяются addDocument (). С меньшими значениями, меньше ОЗУ используется при индексации , и поиски по неоптимизированным индексам быстрее, но скорость индексации медленнее. При больших значениях используется больше оперативной памяти при индексации и при поиске на неоптимизированные индексы медленнее, индексация быстрее. Таким образом, большие значения (> 10) лучше всего подходят для индекса партии создание и меньшие значения (<10) для индексов, которые в интерактивном режиме поддерживается. </p>

Этот метод является вспомогательным, он использует оперативную память при увеличении mergeFactor

То, что я хотел бы предложить, это установить что-то вроде 15 или около того .; (методом проб и ошибок), дополненный setRAMBufferSizeMB, также вызовите Commit () . затем optimize () и затем close () объект indexwriter. (возможно, сделайте JavaBean и поместите все эти методы в один метод), вызывайте этот метод при закрытии индекса. 1031 *

пост с вашим результатом, обратная связь =]

2 голосов
/ 23 сентября 2010

Для пользователей в спящем режиме (с использованием mysql), а также с использованием grails (с помощью плагина с возможностью поиска).

Я продолжал получать ошибки OOM при индексации строк 3M и общего объема данных 5GB.

Эти настройки, похоже, устранили проблему без необходимости писать какие-либо пользовательские индексаторы.

вот несколько вещей, которые стоит попробовать:

Настройки компаса:

        'compass.engine.mergeFactor':'500',
        'compass.engine.maxBufferedDocs':'1000'

и для спящего режима (не уверен, если это необходимо, но может помочь, например, esp w / mysql, у которого потоковая передача результатов jdbc отключена по умолчанию.

        hibernate.jdbc.batch_size = 50  
        hibernate.jdbc.fetch_size = 30
        hibernate.jdbc.use_scrollable_resultset=true

Также, похоже, специально для mysql, пришлось добавить некоторые параметры url в строку подключения jdbc.

        url = "jdbc:mysql://127.0.0.1/mydb?defaultFetchSize=500&useCursorFetch=true"

(обновление: с параметрами url память не превышает 500 МБ)

В любом случае, теперь я могу построить свой индекс lucene / comapss с размером кучи менее 2 ГБ. Ранее мне нужно было 8 ГБ, чтобы избежать OOM. Надеюсь, это кому-нибудь поможет.

[1]: http://dev.mysql.com/doc/refman/5.0/en/connector-j-reference-implementation-notes.html mysql streaming jdbc resultset

1 голос
/ 01 сентября 2009

Профилирование - единственный способ определить такое большое потребление памяти.

Кроме того, в своем коде вы не закрываете Файловые обработчики, индексаторы, индексаторы , возможно, виновник OOM,

0 голосов
/ 31 октября 2009

Ранее в этом году мы столкнулись с некоторыми проблемами «нехватки памяти» при создании наших поисковых индексов для нашей поисковой системы хранилища maven на jarvana.com . Мы строили индексы на 64-битной четырехъядерной машине Windows Vista, но у нас работала 32-битная Java и 32-битная Eclipse. У нас было 1,5 ГБ оперативной памяти, выделенной для JVM. Мы использовали Lucene 2.3.2. Приложение индексирует около 100 ГБ в основном сжатых данных, а наши индексы составляют около 20 ГБ.

Мы попробовали несколько вещей, таких как очистка IndexWriter, явный вызов сборщика мусора через System.gc (), попытка разыменования всего возможного и т. Д. Мы использовали JConsole для мониторинга использования памяти. Как ни странно, мы довольно часто сталкивались с ошибками «OutOfMemoryError: пространство кучи Java», когда их не должно было быть, основываясь на том, что мы видели в JConsole. Мы попытались перейти на разные версии 32-битной Java, но это не помогло.

В итоге мы перешли на 64-битную Java и 64-битную Eclipse. Когда мы сделали это, наши кучи памяти во время индексации исчезали при работе с 1,5 ГБ, выделенными для 64-битной JVM. Кроме того, переход на 64-битную Java позволил нам выделить больше памяти для JVM (мы перешли на 3 ГБ), что ускорило нашу индексацию.

Не уверен, что именно предложить, если вы используете XP. Для нас проблемы OutOfMemoryError, похоже, были связаны с Windows Vista 64 и 32-битной Java. Возможно, может помочь переход на работу на другом компьютере (Linux, Mac, другая Windows). Я не знаю, исчезли ли наши проблемы навсегда, но, похоже, они уже ушли.

0 голосов
/ 02 сентября 2009

Вы можете установить IndexWriter на сброс в зависимости от использования памяти или количества документов - я бы посоветовал установить его на flsuh в зависимости от памяти и посмотреть, решит ли это вашу проблему. Я предполагаю, что весь ваш индекс живет в памяти, потому что вы никогда не записываете его на диск.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...