編者注:咱們發現了有趣的系列文章《30天學習30種新技術》,正在翻譯,一天一篇更新,年終禮包。下面是第 20 天的內容。html
今天學習如何使用斯坦福CoreNLP Java API來進行情感分析(sentiment analysis)。前幾天,我還寫了一篇關於如何使用TextBlob API在Python裏作情感分析,我已經開發了一個應用程序,會篩選出給定關鍵詞的推文(tweets)的情感,如今看看它能作什麼。java
該演示應用程序在OpenShift http://sentiments-t20.rhcloud.com/ 運行,它有兩個功能:git
第一個功能是,若是你給定Twitter搜索條件的列表會,它會顯示最近20推關於給定的搜索詞的情緒。必需要勾選下圖所示的複選框來啓用此功能,(情感)積極的推文將顯示綠色,而消極的推文是紅色的。
github
第二個功能是作一些文字上的情感分析,以下圖
web
斯坦福CoreNLP是一個Java天然語言分析庫,它集成了全部的天然語言處理工具,包括詞性的終端(POS)標註器,命名實體識別(NER),分析器,對指代消解系統,以及情感分析工具,並提供英語分析的模型文件。segmentfault
sudo gem install rhc
,確保它是最新版本。要更新RHC的話,執行命令 sudo gem update rhc
,如需其餘協助安裝RHC命令行工具,請參閱該頁面: https://www.openshift.com/developers/rhc-client-tools-installrhc setup
命令設置您的OpenShift賬戶,此命令將幫助你建立一個命名空間,並上傳你的SSH keys到OpenShift服務器。今天的演示應用程序的代碼能夠在GitHub找到:day20-stanford-sentiment-analysis-demo數組
開始建立應用程序,名稱爲sentimentsapp
。ruby
$ rhc create-app sentimentsapp jbosseap --from-code=https://github.com/shekhargulati/day20-stanford-sentiment-analysis-demo.git
還可使用以下指令:服務器
$ rhc create-app sentimentsapp jbosseap -g medium --from-code=https://github.com/shekhargulati/day20-stanford-sentiment-analysis-demo.git
這將爲應用程序建立一個容器,設置全部須要的SELinux政策和cgroup的配置,OpenShift也將建立一個私人git倉庫並克隆到本地。而後,它會複製版本庫到本地系統。最後,OpenShift會給外界提供一個DNS,該應用程序將在http://newsapp-{domain-name}.rhcloud.com/ 下能夠訪問(將 domain-name 更換爲本身的域名)。oracle
該應用程序還須要對應Twitter應用程序的4個環境變量,經過去https://dev.twitter.com/apps/new 建立一個新的Twitter應用程序,而後建立以下所示的4個環境變量。
$ rhc env set TWITTER_OAUTH_ACCESS_TOKEN=<please enter value> -a sentimentsapp $ rhc env set TWITTER_OAUTH_ACCESS_TOKEN_SECRET=<please enter value> -a sentimentsapp $rhc env set TWITTER_OAUTH_CONSUMER_KEY=<please enter value> -a sentimentsapp $rhc env set TWITTER_OAUTH_CONSUMER_SECRET=<please enter value> -a sentimentsapp
從新啓動應用程序,以確保服務器能夠讀取環境變量。
$ rhc restart-app --app sentimentsapp
開始在pom.xml
中爲stanford-corenlp
和twitter4j
增長Maven的依賴關係,使用3.3.0版本斯坦福corenlp做爲情感分析的API。
<dependency> <groupId>edu.stanford.nlp</groupId> <artifactId>stanford-corenlp</artifactId> <version>3.3.0</version> </dependency> <dependency> <groupId>org.twitter4j</groupId> <artifactId>twitter4j-core</artifactId> <version>[3.0,)</version> </dependency>
該twitter4j依賴關係須要Twitter搜索。
經過更新 pom.xml
文件裏的幾個特性將Maven項目更新到Java 7:
<maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target>
如今就能夠更新Maven項目了(右鍵單擊>Maven>更新項目)。
使用CDI來進行依賴注入。CDI、上下文和依賴注入是一個Java EE 6規範,可以使依賴注入在Java EE 6的項目中。
在 src/main/webapp/WEB-INF
文件夾下建一個名爲beans.xml
中一個新的XML文件,啓動CDI
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> </beans>
建立了一個新的類TwitterSearch
,它使用Twitter4J API來搜索Twitter關鍵字。該API須要的Twitter應用程序配置參數,使用的環境變量獲得這個值,而不是硬編碼。
import java.util.Collections; import java.util.List; import twitter4j.Query; import twitter4j.QueryResult; import twitter4j.Status; import twitter4j.Twitter; import twitter4j.TwitterException; import twitter4j.TwitterFactory; import twitter4j.conf.ConfigurationBuilder; public class TwitterSearch { public List<Status> search(String keyword) { ConfigurationBuilder cb = new ConfigurationBuilder(); cb.setDebugEnabled(true).setOAuthConsumerKey(System.getenv("TWITTER_OAUTH_CONSUMER_KEY")) .setOAuthConsumerSecret(System.getenv("TWITTER_OAUTH_CONSUMER_SECRET")) .setOAuthAccessToken(System.getenv("TWITTER_OAUTH_ACCESS_TOKEN")) .setOAuthAccessTokenSecret(System.getenv("TWITTER_OAUTH_ACCESS_TOKEN_SECRET")); TwitterFactory tf = new TwitterFactory(cb.build()); Twitter twitter = tf.getInstance(); Query query = new Query(keyword + " -filter:retweets -filter:links -filter:replies -filter:images"); query.setCount(20); query.setLocale("en"); query.setLang("en");; try { QueryResult queryResult = twitter.search(query); return queryResult.getTweets(); } catch (TwitterException e) { // ignore e.printStackTrace(); } return Collections.emptyList(); } }
在上面的代碼中,篩選了Twitter的搜索結果,以確保沒有轉推(retweet)、或帶連接的推文、或有圖片的推文,這樣作的緣由是爲了確保咱們獲得的是有文字的推。
建立了一個叫SentimentAnalyzer
的類,這個類就是對某一條推文進行情感分析的。
public class SentimentAnalyzer { public TweetWithSentiment findSentiment(String line) { Properties props = new Properties(); props.setProperty("annotators", "tokenize, ssplit, parse, sentiment"); StanfordCoreNLP pipeline = new StanfordCoreNLP(props); int mainSentiment = 0; if (line != null && line.length() > 0) { int longest = 0; Annotation annotation = pipeline.process(line); for (CoreMap sentence : annotation.get(CoreAnnotations.SentencesAnnotation.class)) { Tree tree = sentence.get(SentimentCoreAnnotations.AnnotatedTree.class); int sentiment = RNNCoreAnnotations.getPredictedClass(tree); String partText = sentence.toString(); if (partText.length() > longest) { mainSentiment = sentiment; longest = partText.length(); } } } if (mainSentiment == 2 || mainSentiment > 4 || mainSentiment < 0) { return null; } TweetWithSentiment tweetWithSentiment = new TweetWithSentiment(line, toCss(mainSentiment)); return tweetWithSentiment; } }
複製 englishPCFG.ser.gz
和 sentiment.ser.gz
模型到src/main/resources/edu/stanford/nlp/models/lexparser
和src/main/resources/edu/stanford/nlp/models/sentiment
文件夾下。
最後,建立了JAX-RS資源類。
public class SentimentsResource { @Inject private SentimentAnalyzer sentimentAnalyzer; @Inject private TwitterSearch twitterSearch; @GET @Produces(value = MediaType.APPLICATION_JSON) public List<Result> sentiments(@QueryParam("searchKeywords") String searchKeywords) { List<Result> results = new ArrayList<>(); if (searchKeywords == null || searchKeywords.length() == 0) { return results; } Set<String> keywords = new HashSet<>(); for (String keyword : searchKeywords.split(",")) { keywords.add(keyword.trim().toLowerCase()); } if (keywords.size() > 3) { keywords = new HashSet<>(new ArrayList<>(keywords).subList(0, 3)); } for (String keyword : keywords) { List<Status> statuses = twitterSearch.search(keyword); System.out.println("Found statuses ... " + statuses.size()); List<TweetWithSentiment> sentiments = new ArrayList<>(); for (Status status : statuses) { TweetWithSentiment tweetWithSentiment = sentimentAnalyzer.findSentiment(status.getText()); if (tweetWithSentiment != null) { sentiments.add(tweetWithSentiment); } } Result result = new Result(keyword, sentiments); results.add(result); } return results; } }
上述代碼執行如下操做:
今天就是這些,歡迎反饋。
原文 Day 20: Stanford CoreNLP--Performing Sentiment Analysis of Twitter using Java
翻譯整理 SegmentFault