Разбор XML с использованием нескольких потоков в Java - PullRequest
0 голосов
/ 01 мая 2020

Я читаю большие XML около 4 ГБ в java, используя JAXB, у меня хорошая система с твердотельными накопителями, оперативной памятью и несколькими ядрами процессора. Я хочу прочитать этот XML файл, используя несколько потоков. Я исследовал это, но еще не нашел никакого решения.

Я думал, что если я смогу прочитать XML, используя несколько потоков, и отправить куски байтов для анализа через синтаксический анализатор XML, это будет хорошо, но интересно, есть ли уже решение с реализацией.

Мой фрагмент кода

public void parseXML() throws Exception{

    try(InputStream is = new BufferedInputStream(new FileInputStream(xmlFile),XML_READ_BUFFER)){
    //try(InputStream is = new ByteArrayInputStream(removeAnd.getBytes(StandardCharsets.UTF_16))){ 
        XMLInputFactory xmlif = XMLInputFactory.newInstance();
        XMLStreamReader sr = xmlif.createXMLStreamReader(is);

        JAXBContext ctx = JAXBContext.newInstance(XwaysImage.class);
        Unmarshaller unmar = ctx.createUnmarshaller();

        int c=0;
        while (sr.hasNext()){

            while(this.pause.get())Thread.sleep(100);
            if(this.cancel.get()) break;

            int eventType = sr.next();
            if(eventType == XMLStreamConstants.START_ELEMENT){
                if("ImageFile".equals(sr.getName().getLocalPart())){
                    XwaysImage xim = unmar.unmarshal(sr,XwaysImage.class).getValue();
                    //TODO code here. 
                }
            }
        }
        sr.close();
        is.close();
    }catch(Exception e){
        log.error("",e);
    }
}

Ответы [ 5 ]

0 голосов
/ 07 мая 2020

Может быть, вы можете попробовать декларативное потоковое сопоставление (DSM) библиотека. Это очень хорошо для обработки больших или сложных документов XML и JSON. Необходимо определить соответствие между данными класса end XML в файле YAML.

Например, допустим, у вас есть файл xml ниже:

<root>
  <item >
    <id>1</id>
    <name>Item 1</name>
  </item>
  <item >
    <id>2</id>
    <name>Item 2</name>
    <date>13/06/2019</date>
  </item>
  <item >
    <id>3</id>
    <name>Item 3</name>
    <date>11/06/2019</date>
  </item>
  <!-- 
  .........
  -->
</root>

Определите отображение для данных, которые вы хотите обработать

result:
   type: object  // it will only store one item in memory.
   path: /root/item    # path is regex can be writen as "/.+item".
   function: processData   # call processData function for every item.
   filter: self.index%params.threadCount==params.threadNo  // you can write script to filter data.
   fields:
     id: long   # id dataType long
     name:      # default dataType string         
     registerDate:   
        path: date
        dataType: date   # data type is date
        dataTypeParams: 
           dateFormat: dd/MM/yyyy  # date format

Напишите функцию для выполнения вашего данные и зарегистрируйте их в файле сопоставления, как показано выше.

FunctionExecutor processData = new FunctionExecutor() {
        @Override
        public void execute(Params params) {
            System.out.println(params.getCurrentNode().getData());
        }
    };

    // java 8+
    //FunctionExecutor processData = params->System.out.println(params.getCurrentNode().getData());

Вот код java. Вы можете установить threadNo для каждого потока. Я предполагаю, что вы будете запускать код в 10 потоке. Для этого примера поток не равен 1. Это означает, что вы будете обрабатывать только элемент, который соответствует фильтр поле в файле отображения.

DSMBuilder builder = new DSMBuilder("path/to/mapping.yaml");
    builder.registerFunction("processData ", processData); // register function
        builder.getParams().put("threadCount", 10);
        builder.getParams().put("threadNo", 1);  // run for first thread
    DSM dsm = builder.create();
    // process json data
    Object object = dsm.toObject("path/to/data.xml");
0 голосов
/ 02 мая 2020

Были проекты, которые пытались применить параллельную обработку к парсингу XML - см., Например, https://www.ibm.com/support/knowledgecenter/en/SSZJPZ_8.7.0/com.ibm.swg.im.iis.ds.stages.xml.core.usage.doc/topics/largescaleparallelparsing.html - но я не знаю, существуют ли инструменты, которые можно использовать на практике. По сути, это не задача, которую легко распараллелить на независимые потоки.

Какая часть затрат в любом случае разбирается? Во многих приложениях 25% могут быть типичными. Если это так, то лучше всего было бы, чтобы один поток выполнял синтаксический анализ, а другие - обрабатывали проанализированные данные.

0 голосов
/ 01 мая 2020
You can make use of Fork/Join Framework added in Java 7. You will need to create RecursiveTask or RecursiveAction as per your needs. Below is the reference to use it.

Please make sure you have multiple cores as you said otherwise it would be of no use.

ForkJoinExmple

0 голосов
/ 01 мая 2020

Поскольку это не синтаксический анализатор в стиле DOM, низкоуровневое чтение файла XML с диска происходит быстро, особенно с SSD. Так что не думайте, что многопоточное чтение поможет там.

Но , многопоточная обработка извлеченных данных может повысить общую производительность, поэтому вместо 'чтения XML с использованием нескольких потоков и отправки кусков байтов разобрать 'попробуйте прочитать в одном потоке, но обрабатывать параллельно.

0 голосов
/ 01 мая 2020

Не уверен, что я полностью понимаю, с какой частью вашего кода вам требуется параллелизм, но если вы используете l oop, вы можете попробовать:

    sr.parallelStream().forEach(-> {
     //do something
})
...