【问题标题】:How to use Stanford CoreNLP java library with Ruby for sentiment analysis?如何使用带有 Ruby 的斯坦福 CoreNLP java 库进行情感分析?
【发布时间】:2015-02-11 20:42:31
【问题描述】:

我正在尝试使用 Ruby on Rails 4、Ruby 2.1.2 和 Mongoid ORM 在本地 MongoDB 实例中对 大量推文 进行情感分析

我在 Mashape.com 上使用了免费提供的 https://loudelement-free-natural-language-processing-service.p.mashape.com API,但是它在快速推送了几百条推文后开始超时 - 显然它不适合通过数万条推文推文,这是可以理解的。

所以接下来我想我会使用这里推广的斯坦福 CoreNLP 库http://nlp.stanford.edu/sentiment/code.html

默认用法,除了使用Java 1.8代码中的库外,似乎是使用XML输入输出文件。对于我的用例来说,这很烦人,因为我有数以万计的短推文,而不是长文本文件。我想像使用方法一样使用 CoreNLP 并执行 tweets.each 类型的循环。

我想一种方法是用所有推文构建一个 XML 文件,然后从 Java 进程中取出一个并解析它并将其放回数据库,但这对我来说感觉很陌生,而且会很多工作。

所以,我很高兴在上面链接的站点上找到一种从命令行运行 CoreNLP 并接受文本作为标准输入的方法,这样我就不必开始摆弄文件系统了而是将文本作为参数提供。但是,与使用 Loudelement 免费情感分析 API 相比,为每条推文单独启动 JVM 会增加巨大的开销。

现在,我编写的代码既丑陋又慢,但它可以工作。不过,我想知道是否有更好的方法从 Ruby 中运行 CoreNLP java 程序,而不必开始摆弄文件系统(创建临时文件并将它们作为参数提供)或编写 Java 代码?

这是我正在使用的代码:

def self.mass_analyze_w_corenlp # batch run the method in multiple Ruby processes
  todo = Tweet.all.exists(corenlp_sentiment: false).limit(5000).sort(follow_ratio: -1) # start with the "least spammy" tweets based on follow ratio
  counter = 0

  todo.each do |tweet|
    counter = counter+1

    fork {tweet.analyze_sentiment_w_corenlp} # run the analysis in a separate Ruby process

    if counter >= 5 # when five concurrent processes are running, wait until they finish to preserve memory
      Process.waitall
      counter = 0
    end

  end
end

def analyze_sentiment_w_corenlp # run the sentiment analysis for each tweet object
  text_to_be_analyzed = self.text.gsub("'"){" "}.gsub('"'){' '} # fetch the text field of DB item strip quotes that confuse the command line

  start = "echo '"
  finish = "' | java -cp 'vendor/corenlp/*' -mx250m edu.stanford.nlp.sentiment.SentimentPipeline -stdin"
  command_string = start+text_to_be_analyzed+finish # assemble the command for the command line usage below

  output =`#{command_string}` # run the CoreNLP on the command line, equivalent to system('...')
  to_db = output.gsub(/\s+/, "").downcase # since CoreNLP uses indentation, remove unnecessary whitespace
  # output is in the format of "neutral, "positive", "negative" and so on

  puts "Sentiment analysis successful, sentiment is: #{to_db} for tweet #{text_to_be_analyzed}."

  self.corenlp_sentiment = to_db # insert result as a field to the object
  self.save! # sentiment analysis done!
end

【问题讨论】:

  • 考虑编写 Java 服务(WSDL、SOAP、REST 或简单的基于 TCP)并从 Ruby 调用它。这是最常用的方式。如果您能够使用 JRuby,那么直接调用 Java 方法似乎很简单。 Here 描述了在不使用 JRuby 的情况下从 Ruby 调用 Java 代码的方法,但它们看起来很复杂。
  • 你见过 CoreNLP 的 Ruby port 吗?
  • @diasks2,我想我已经看过了,但是根据自述文件,它看起来不像会在其中实施情绪分析。我对 CoreNLP 声称默认包含在其中的深度学习模型非常感兴趣:nlp.stanford.edu/sentiment
  • @herb This 在您的链接的 cmets 中被引用“刚刚发布了一个快速 Ruby 模块来解析和导入情绪树库,请参阅 github.com/someben/treebank” - 我还没有看过它细节,但可能值得一试。

标签: java ruby twitter nlp stanford-nlp


【解决方案1】:

你至少可以通过使用IO.popen打开和与外部进程通信来避免丑陋和危险的命令行,例如:

input_string = "
foo
bar
baz
"

output_string =
    IO.popen("grep 'foo'", 'r+') do |pipe|
        pipe.write(input_string)
        pipe.close_write
        pipe.read
    end

puts "grep said #{output_string.strip} but not bar"

编辑:为避免在每个项目上重新加载 Java 程序的开销,您可以打开 todo.each 循环周围的管道,并像这样与进程通信

inputs = ['a', 'b', 'c', 'd']

IO.popen('cat', 'r+') do |pipe|

    inputs.each do |s|
        pipe.write(s + "\n")
        out = pipe.readline

        puts "cat said '#{out.strip}'"
    end
end

也就是说,如果 Java 程序支持这种行缓冲的“批处理”输入。但是,如果没有,修改它应该不会很困难。

【讨论】:

    【解决方案2】:

    正如@Qualtagh 在 cmets 中所建议的,我决定使用 JRuby

    我第一次尝试使用 Java 来使用 MongoDB 作为接口(直接从 MongoDB 读取,用 Java/CoreNLP 分析并写回 MongoDB),但是 MongoDB Java Driver 使用起来比我使用的 Mongoid ORM 更复杂Ruby,所以这就是我觉得 JRuby 更合适的原因。

    为 Java 做一个 REST 服务需要我首先学习如何用 Java 做一个 REST 服务,这可能很容易,也可能不容易。我不想花时间弄清楚这一点。

    所以我需要执行的代码是:

      def analyze_tweet_with_corenlp_jruby
        require 'java'
        require 'vendor/CoreNLPTest2.jar' # I made this Java JAR with IntelliJ IDEA that includes both CoreNLP and my initialization class
    
        analyzer = com.me.Analyzer.new # this is the Java class I made for running the CoreNLP analysis, it initializes the CoreNLP with the correct annotations etc.
        result = analyzer.analyzeTweet(self.text) # self.text is where the text-to-be-analyzed resides
    
        self.corenlp_sentiment = result # adds the result into this field in the MongoDB model
        self.save!
        return "#{result}: #{self.text}" # for debugging purposes
      end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-07-06
      • 2015-03-16
      • 2015-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多