Ленивый разбор с Stanford CoreNLP, чтобы получить чувство только определенных предложений

Я ищу способы оптимизировать производительность моего конвейера настроений Stanford CoreNLP. В результате возникает желание получить сентиментальные предложения, но только те, которые содержат конкретные ключевые слова, приведенные в качестве входных данных.

Я попробовал два подхода:

Подход 1: конвейер StanfordCoreNLP, аннотирующий весь текст с настроением

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

Это код:

List<String> keywords = ...;
String text = ...;
Map<Integer,Integer> sentenceSentiment = new HashMap<>();

Properties props = new Properties();
props.setProperty("annotators", "tokenize, ssplit, parse, sentiment");
props.setProperty("parse.maxlen", "20");
props.setProperty("tokenize.options", "untokenizable=noneDelete");
StanfordCoreNLP pipeline = new StanfordCoreNLP(props);

Annotation annotation = pipeline.process(text); // takes 2 seconds!!!!
List<CoreMap> sentences = annotation.get(CoreAnnotations.SentencesAnnotation.class);
for (int i=0; i<sentences.size(); i++) {
    CoreMap sentence = sentences.get(i);
    if(sentenceContainsKeywords(sentence,keywords) {
        int sentiment = RNNCoreAnnotations.getPredictedClass(sentence.get(SentimentCoreAnnotations.SentimentAnnotatedTree.class));
        sentenceSentiment.put(sentence,sentiment);
    }
}

Подход 2: конвейер StanfordCoreNLP, аннотирующий весь текст предложениями, отдельные аннотаторы, работающие на интересующих предложениях

Из-за слабой производительности первого решения я определил второе решение. Я определил конвейер с аннотаторами: tokenize, ssplit. Я искал ключевые слова в каждом предложении и, если они присутствовали, я создал аннотацию только для этого предложения и запустил следующие аннотаторы: ParserAnnotator, BinarizerAnnotator и SentimentAnnotator.

Результаты были действительно неудовлетворительными из-за ParserAnnotator. Даже если я инициализировал его с теми же свойствами. Иногда это занимало даже больше времени, чем весь конвейер для документа в подходе 1.

List<String> keywords = ...;
String text = ...;
Map<Integer,Integer> sentenceSentiment = new HashMap<>();

Properties props = new Properties();
props.setProperty("annotators", "tokenize, ssplit"); // parsing, sentiment removed
props.setProperty("parse.maxlen", "20");
props.setProperty("tokenize.options", "untokenizable=noneDelete");
StanfordCoreNLP pipeline = new StanfordCoreNLP(props);

// initiation of annotators to be run on sentences
ParserAnnotator parserAnnotator = new ParserAnnotator("pa", props);
BinarizerAnnotator  binarizerAnnotator = new BinarizerAnnotator("ba", props);
SentimentAnnotator sentimentAnnotator = new SentimentAnnotator("sa", props);

Annotation annotation = pipeline.process(text); // takes <100 ms
List<CoreMap> sentences = annotation.get(CoreAnnotations.SentencesAnnotation.class);
for (int i=0; i<sentences.size(); i++) {
    CoreMap sentence = sentences.get(i);
    if(sentenceContainsKeywords(sentence,keywords) {
        // code required to perform annotation on one sentence
        List<CoreMap> listWithSentence = new ArrayList<CoreMap>();
        listWithSentence.add(sentence);
        Annotation sentenceAnnotation  = new Annotation(listWithSentence);

        parserAnnotator.annotate(sentenceAnnotation); // takes 50 ms up to 2 seconds!!!!
        binarizerAnnotator.annotate(sentenceAnnotation);
        sentimentAnnotator.annotate(sentenceAnnotation);
        sentence = sentenceAnnotation.get(CoreAnnotations.SentencesAnnotation.class).get(0);

        int sentiment = RNNCoreAnnotations.getPredictedClass(sentence.get(SentimentCoreAnnotations.SentimentAnnotatedTree.class));
        sentenceSentiment.put(sentence,sentiment);
    }
}

Вопросы

Интересно, почему парсинг в CoreNLP не "ленивый"? (В моем примере это означало бы: выполняется только тогда, когда вызывается мнение о предложении). Это из соображений производительности?

Почему парсер для одного предложения может работать почти столько же, сколько парсер для всей статьи (в моей статье было 7 предложений)? Можно ли настроить его так, чтобы он работал быстрее?

Ответы на вопрос(1)

Ваш ответ на вопрос