Использование VTD в многопоточном приложении

У меня есть огромные xmls, в результате у меня много xpaths для извлечения записей из xml. Поэтому я пытаюсь создать несколько потоков, чтобы каждый xpath мог оцениваться в другом потоке. Но я получаю ошибки ниже, это код фрагмент, который может дать хорошее представление, я использовал здесь очень маленький xml для краткости. Я создаю 3 потока и ставлю в очередь 10 задач.

import java.io.File;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import com.ximpleware.AutoPilot;
import com.ximpleware.EOFException;
import com.ximpleware.EncodingException;
import com.ximpleware.EntityException;
import com.ximpleware.ParseException;
import com.ximpleware.VTDGen;
import com.ximpleware.VTDNav;

public class MultiThread {
    public static void main(String args[]) throws InterruptedException, ExecutionException, EncodingException, EOFException, EntityException, ParseException
    {
        String str="<library><booked>book</booked> <book id=\"1\"> <title>Googled By God</title>  </book> </library>";
        File f = new File("/home/cloudera/wos.xml");
        byte[] ba =null;;
        ExecutorService executor = Executors.newFixedThreadPool(3);
        List<Task> extractorTasks = new ArrayList<Task>();
        VTDGen vg = new VTDGen();
        vg.setDoc(str.getBytes());
        vg.parse(false);


        //add 10 tasks
        for(int i=0;i<10;i++)
        {

            Task d = new Task(str.getBytes(),vg,"/library/book/title");
            extractorTasks.add(d);
        }

        List<Future<String>> output = executor.invokeAll(extractorTasks);
        executor.shutdown();    
    }
}
class Task implements Callable<String> {

    VTDGen vg = null;
    String xpath = "";
    byte [] ba=null;
    AutoPilot ap = null;
    Task(byte[] _ba,VTDGen _vg,String _xpath)
    {
        ba = _ba;
        vg = _vg;
        xpath = _xpath;
    }
    public String call() throws Exception 
    {

        String title = "";
        try 
        {
            /* if we uncomment below 3 lines, all works well, thats becuase we are reparsing the whole document*/
            //vg = new VTDGen();
            //vg.setDoc(ba);
            //vg.parse(false);

            VTDNav vn = vg.getNav();
            ap = new AutoPilot(vn);
            ap.selectXPath(xpath);

            //Get all the titles and print each of those
            while(ap.evalXPath() != -1)
            {
                //getText will return the index of  the VTDRecord
                int titleIndex = vn.getText();
                //Get the text of the VTDRecord
                title = vn.toNormalizedString(titleIndex);
                System.out.println("Title is "+title);
            }

            vn.toElement(VTDNav.ROOT);

        }  
        catch (Exception e) {
            e.printStackTrace();
        }

        return title;
    }

}

person BJC    schedule 03.02.2018    source источник
comment
В чем проблема?   -  person xingbin    schedule 03.02.2018
comment
Я сталкиваюсь с исключениями, такими как java.lang.IllegalArgumentException в com.ximpleware.UniByteBuffer.‹init›(UniByteBuffer.java:32) в com.ximpleware.VTDGen.getNav(VTDGen.java:1745)   -  person BJC    schedule 03.02.2018
comment
Пожалуйста, прочтите Как задать хороший вопрос?, прежде чем пытаться задать дополнительные вопросы.   -  person    schedule 03.02.2018


Ответы (1)


Мне удалось найти исправление. Я храню VTDNav в переменной и передаю его «дубликат» каждой задаче. Вызов GetNav() очищает внутреннее состояние, что, возможно, также приводит к аннулированию VTDnav, поэтому сохранение копии навигатора и передача дубликата навигатора помогли.

import java.io.File;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import com.ximpleware.AutoPilot;
import com.ximpleware.EOFException;
import com.ximpleware.EncodingException;
import com.ximpleware.EntityException;
import com.ximpleware.ParseException;
import com.ximpleware.VTDGen;
import com.ximpleware.VTDNav;

public class MultiThread {
    public static void main(String args[]) throws InterruptedException, ExecutionException, EncodingException, EOFException, EntityException, ParseException
    {
        String str="<library><booked>book</booked> <book id=\"1\"> <title>Googled By God</title>  </book> </library>";
        File f = new File("/home/cloudera/wos.xml");
        byte[] ba =null;;
        ExecutorService executor = Executors.newFixedThreadPool(5);
        List<Task> extractorTasks = new ArrayList<Task>();
        VTDGen vg = new VTDGen();
        vg.setDoc(str.getBytes());
        vg.parse(false);

        //The GetNav() call cleans internal state , so keep a copy of VTDNav
        VTDNav vn = vg.getNav();

        for(int i=0;i<100;i++)
        {
            //pass the duplicates of navigator
            Task d = new Task(str.getBytes(),vn.duplicateNav(),"/library/book/title");
            extractorTasks.add(d);
        }

        List<Future<String>> output = executor.invokeAll(extractorTasks);
        executor.shutdown();    
    }
}
class Task implements Callable<String> {

    VTDGen vg = null;
    String xpath = "";
    byte [] ba=null;
    VTDNav vn = null;
    AutoPilot ap = null;
    Task(byte[] _ba,VTDNav _vn,String _xpath)
    {
        ba = _ba;
        vn = _vn;
        xpath = _xpath;
    }
    public String call() throws Exception 
    {

        String title = "";
        try 
        {
            ap = new AutoPilot(vn);
            //Thread.sleep(500);
            ap.selectXPath(xpath);

            //Get all the titles and print each of those
            while(ap.evalXPath() != -1)
            {
                //getText will return the index of  the VTDRecord
                int titleIndex = vn.getText();
                //Get the text of the VTDRecord
                title = vn.toNormalizedString(titleIndex);
                System.out.println("Title is "+title);
            }

            //if(vn.toElement(VTDNav.ROOT) == true)
            //  System.out.println("to element failed");

        }  
        catch (Exception e) {
            e.printStackTrace();
            System.out.println("Message is "+e.getMessage());
        }

        return title;
    }

}
person BJC    schedule 03.02.2018
comment
Это правильное решение для вашего случая... Я должен отметить, что однажды меня попросили поделиться объектом xpath для одного и того же xpath между несколькими потоками... мой ответ состоял в том, чтобы скомпилировать одно и то же выражение xpath в несколько объектов autoPilot... , не делитесь ими вообще.... надеюсь, у вас нет этой проблемы... - person vtd-xml-author; 03.02.2018