2016-06-29 2 views
0

Мне нужно запросить файл электронной таблицы на Java. Я использую Apache MetaModel.Apache MetaModel - таблица с плохими результатами запросов

я импортировать его с использованием Maven

<dependency> 
    <groupId>org.apache.metamodel</groupId> 
    <artifactId>MetaModel-excel</artifactId> 
    <version>4.5.2</version> 
</dependency> 

Все работает нормально, но next() инструкции, когда он должен вернуться ложным занимает несколько секунд, то почему?

import org.apache.metamodel.DataContext; 
import org.apache.metamodel.excel.ExcelDataContext; 
import org.apache.metamodel.schema.Schema; 
import org.apache.metamodel.schema.Column; 
import org.apache.metamodel.schema.Table; 
import org.apache.metamodel.query.Query; 
import org.apache.metamodel.query.OperatorType; 
import org.apache.metamodel.data.DataSet; 
import org.apache.metamodel.data.Row; 
import org.apache.metamodel.MetaModelException; 


public class SpreadsheetReader { 

    private File spreadsheet; 


    public SpreadsheetReader(String spreadsheetLocation, String spreadsheetName){ 

     this.spreadsheet = new File(spreadsheetLocation + spreadsheetName); 

     if(!"OK".equals(checkSpreadSheet())){ 
      throw new IllegalStateException("Error in spreadsheet. Cause: "+spreadsheetStatus); 
     } 

    } 


    /** query the excel spreadsheet for the given ID 
    */ 
    public List<String> query(String givenProgId){ 

     List<String> linksArray = new ArrayList<String>(); 
     int rowCount = 0; 

     ExcelConfiguration conf = new ExcelConfiguration(1, true, true); // columnNameLineNumber, skipEmptyLines, sEColumns 
     DataContext dataContext = new ExcelDataContext(this.spreadsheet, conf); 

     System.out.println("PROFILING >>> "+(new org.joda.time.DateTime())+" START-1"); // ## 

     Schema schema = dataContext.getDefaultSchema(); 

     System.out.println("PROFILING >>> "+(new org.joda.time.DateTime())+" STOP-1"); // ## 
     // Takes 2 seconds. Will be moved into constructor. 

     Table table = schema.getTables()[0]; 

     Column idsColumn = table.getColumnByName("ProgID"); 
     Column titlesColumn = table.getColumnByName("Titles"); 

     Query query = new Query().select(titlesColumn) 
           .from(table) 
           .where(idsColumn, OperatorType.EQUALS_TO, givenProgId); 

     try(DataSet dataSet = dataContext.executeQuery(query)){ // try-with-resource, no need to close dataset 

      while (dataSet.next()) { 

       // the rows are read quite quickly, problem will be when next() is false 

       ++rowCount; 

       Row currentRow = dataSet.getRow(); 
       String currentTitle = (String)currentRow.getValue(0); 

       linksArray.add("my-service/titles/"+currentTitle); 

       System.out.println("PROFILING >>> "+(new org.joda.time.DateTime())+" START-2"); // @@@@@@@ 
      } 
      System.out.println("PROFILING >>> "+(new org.joda.time.DateTime())+" STOP-2"); // @@@@@@@ 
      // TAKES ABOUT 6 SECONDS - (Excel file has just 14.779 rows and 114 columns) 

     }catch(MetaModelException xx){ 
      //logger 
      throw xx; 
     } 

     return linksArray; 
    } 
}} 

UPDATE: Некоторые более профилирование с табличный документ только с 3 записей:

Код сейчас:

try(DataSet dataSet = this.dataContext.executeQuery(query)){ 


    // FIRST NEXT() with result => quite fast 

    System.out.println("\n PROFILING >>> "+(new org.joda.time.DateTime())+" START a\n"); 
    System.out.println("\n 88888 NEXT >>> "+(dataSet.next())+" <<<< \n"); 
    Row currentRow = dataSet.getRow(); 
    String currentTitle = (String)currentRow.getValue(0); 
    System.out.println("\n READ: "+(new org.joda.time.DateTime())+" >>> "+currentTitle+" \n"); 

    System.out.println("\n PROFILING >>> "+(new org.joda.time.DateTime())+" STOP a\n"); 


    // SECOND AND LAST NEXT() => very SLOW 

    System.out.println("\n PROFILING >>> "+(new org.joda.time.DateTime())+" START b\n"); 
    System.out.println("\n 88888 NEXT >>> "+(dataSet.next())+" <<<< \n"); 
    System.out.println("\n PROFILING >>> "+(new org.joda.time.DateTime())+" STOP b\n"); 

} 

И таблица предварительно загруженных в класса.

Бревна (с раз) для последнего из серии последовательных идентичных запросов являются:

Jun 30, 2016 10:59:38 AM log my-project.logging.ITVLogger 
INFO: CODE00012 - Query on spreadsheet started for ID 123456 



PROFILING >>> 2016-06-30T10:59:38.651+01:00 START a 

10:59:38.652 [main] INFO o.a.m.d.RowPublisherDataSet - 
Starting separate thread for publishing action: [email protected] 

88888 NEXT >>> true <<<< 

READ: 2016-06-30T10:59:39.756+01:00 >>> A_TITLE 

PROFILING >>> 2016-06-30T10:59:39.756+01:00 STOP a 



PROFILING >>> 2016-06-30T10:59:39.756+01:00 START b 

88888 NEXT >>> false <<<< 

PROFILING >>> 2016-06-30T10:59:44.735+01:00 STOP b 

Таким образом, чтобы резюмировать это занимает около одной секунды, чтобы получить результат и 4 ~ 6 секунд для последнего исполнение next().

+0

После первого '' 'next()' '' журнала приложений '' 'o.a.m.d.RowPublisherDataSet - запуск отдельного потока для публикации действия: org.apache.metamodel.excel.XlsxRowPublisherAction @ 3d6e18b4'''. Может ли он ждать его прекращения? –

+0

Переключение на github.com/monitorjbl/excel-streaming-reader, чтение всего документа при запуске и сохранение столбцов, которые мне нужны в памяти на карте, поэтому последующие запросы быстрее –

ответ

1

Реализация excel DataContext позволяет разворачивать и анализировать zipped-файл xlsx в фоновом режиме. Это означает, что метод DataContext.executeQuery(...) быстро возвращается, но вызов DataSet.next(), который появляется сразу после того, как ему нужно дождаться, когда данные будут доступны в памяти. Я не вижу никакого способа избежать этого, это просто следствие того, что файлы Excel являются довольно сложными для решения.

+0

Да, но дело в том, что мы просто имеем одна строка в результате, первый вызов '' 'dataset.next()' '' и следующий '' 'dataset.getRow(). getValue (0)' '' довольно быстро распечатывает значение, полученное из электронной таблицы (менее чем за одну секунду), но когда он вызывает '' 'dataset.next()' '' второй раз (это возвращает false), для завершения вызова требуется 4 ~ 8 секунд. Это узкое место, и мне интересно, почему это происходит. Я также попытался инициализировать DataSet в конструкторе, но любой последующий запрос имеет одинаковую задержку. Спасибо. Ниццкая библиотека, кстати, очень читаема :) –

+0

'' DataContext''' теперь инициализируется в конструкторе, теперь в электронной таблице всего 3 записи => последний следующий() выполняется еще 6 секунд ** для каждого запроса ** –

+1

Это очень интересное наблюдение. Я бы предложил повысить его как потенциальную ошибку в списке рассылки разработчиков MetaModel. Нужно было погрузиться в него глубже, чтобы узнать, действительно ли это ошибка, или если это что-то еще. –

Смежные вопросы