Análise preguiçosa com Stanford CoreNLP para obter sentimentos apenas de frases específicas

Estou procurando maneiras de otimizar o desempenho do meu pipeline de sentimentos Stanford CoreNLP. Como resultado, você deseja obter sentimentos de sentenças, mas apenas aquelas que contêm palavras-chave específicas fornecidas como entrada.

Eu tentei duas abordagens:

Abordagem 1: pipeline StanfordCoreNLP anotando texto inteiro com sentimento

Eu defini um pipeline de anotadores: tokenize, ssplit, analise, sentiment. Eu o executei no artigo inteiro, procurei palavras-chave em cada frase e, se elas estivessem presentes, execute um método que retorne o valor da palavra-chave. Não fiquei satisfeito com o fato de o processamento demorar alguns segundos.

Este é o código:

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);
    }
}

Abordagem 2: pipeline StanfordCoreNLP anotando texto inteiro com frases, anotadores separados sendo executados em frases de interesse

Devido ao fraco desempenho da primeira solução, eu defini a segunda solução. Eu defini um pipeline com anotadores: tokenize, ssplit. Procurei palavras-chave em cada frase e, se elas estivessem presentes, criei uma anotação apenas para essa frase e executei os próximos anotadores: ParserAnnotator, BinarizerAnnotator e SentimentAnnotator.

Os resultados foram realmente insatisfatórios por causa do ParserAnnotator. Mesmo se eu o inicializei com as mesmas propriedades. Às vezes, demorava ainda mais tempo do que todo o pipeline executado em um documento na Abordagem 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);
    }
}

Questões

Gostaria de saber por que analisar no CoreNLP não é "preguiçoso"? (No meu exemplo, isso significaria: realizado apenas quando o sentimento de uma frase é chamado). É por razões de desempenho?

Como um analisador de uma frase pode funcionar quase tanto quanto um analisador de um artigo inteiro (meu artigo tinha 7 frases)? É possível configurá-lo de uma maneira que funcione mais rápido?

questionAnswers(1)

yourAnswerToTheQuestion