1. 程式人生 > >將Stanford CoreNLP的解析結果構造為json格式

將Stanford CoreNLP的解析結果構造為json格式

首次處理英文語料,需要進行一些基礎的NLP處理,首選工具當然是Stanford CoreNLP。由於Stanford CoreNLP官方示例的解析結果不宜直接使用,所以我在它的基礎上進行修改,最終將解析結果轉為json格式,並依照哈工大ltp的解析結果的格式,將依存句法的解析結果也新增到json中。

1、Stanford CoreNLP的安裝

最新版的Stanford CoreNLP僅支援jdk1.8,這比較奇葩,因為目前多數機器的jdk還只是1.6或1.7,最以我下載了支援jdk1.6的最後一個版本,地址:http://nlp.stanford.edu/software/stanford-corenlp-full-2014-08-27.zip
 。下載完成後,將解壓後的所有內容放到(Eclipse)專案的根目錄下,通過Build Path將所有的jar包新增到專案庫中,即可完成安裝配置。解壓後的目錄中有一個名為StanfordCoreNlpDemo.java的示例檔案,簡潔地展示瞭如何使用此工具,但是它使用的結果顯示方式是prettyPrint,這種結果只便於人來看,而不便於機器來獲取。所以我以 http://www.cnblogs.com/tec-vegetables/p/4153144.html所示的例子來基礎來改寫程式碼。
2、程式碼,有詳細解釋
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sf.json.JSONArray;
import edu.stanford.nlp.dcoref.CorefChain;
import edu.stanford.nlp.ling.CoreAnnotations.CharacterOffsetBeginAnnotation;
import edu.stanford.nlp.ling.CoreAnnotations.CharacterOffsetEndAnnotation;
import edu.stanford.nlp.ling.CoreAnnotations.LemmaAnnotation;
import edu.stanford.nlp.ling.CoreAnnotations.NamedEntityTagAnnotation;
import edu.stanford.nlp.ling.CoreAnnotations.PartOfSpeechAnnotation;
import edu.stanford.nlp.ling.CoreAnnotations.SentencesAnnotation;
import edu.stanford.nlp.ling.CoreAnnotations.TextAnnotation;
import edu.stanford.nlp.ling.CoreAnnotations.TokensAnnotation;
import edu.stanford.nlp.ling.CoreLabel;
import edu.stanford.nlp.pipeline.Annotation;
import edu.stanford.nlp.pipeline.StanfordCoreNLP;
import edu.stanford.nlp.semgraph.SemanticGraph;
import edu.stanford.nlp.semgraph.SemanticGraphCoreAnnotations.CollapsedCCProcessedDependenciesAnnotation;
import edu.stanford.nlp.trees.Tree;
import edu.stanford.nlp.trees.TreeCoreAnnotations.TreeAnnotation;
import edu.stanford.nlp.util.CoreMap;

public class TestCoreNLP 
{
	//引數text為需要處理的句子
	public static void run(String text)
	{
		//建立一個corenlp物件,設定需要完成的任務。
		//tokenize: 分詞;ssplit:分句;pos:詞性標註;lemma:獲取詞原型;parse:句法解析(含依存句法);dcoref:同義指代    	
		Properties props = new Properties();
		props.put("annotators", "tokenize, ssplit, pos, lemma, ner, parse, dcoref");
		StanfordCoreNLP pipeline = new StanfordCoreNLP(props);

		// 建立一個基於引數句子的標註物件
		Annotation document = new Annotation(text);

		// 將上述標註物件將對corenlp進行處理
		pipeline.annotate(document);

		// 獲取處理結果
		List<CoreMap> sentences = document.get(SentencesAnnotation.class);

		//遍歷所有句子,輸出每一句的處理結果        
		for(CoreMap sentence: sentences)
		{
			//遍歷句子中每一個詞,獲取其解析結果並構造json資料
			JSONArray jsonSent = new JSONArray(); //建立一個json陣列,用於儲存當前句子的最終所有解析結果
			int id=1;//當前詞在句子中的id,從1開始,因為原始的解析結果就是從1開始的。

			//先獲取當前句子的依存句法分析結果			
			SemanticGraph dependencies = sentence.get(CollapsedCCProcessedDependenciesAnnotation.class);
			//遍歷每一個詞
			for (CoreLabel token: sentence.get(TokensAnnotation.class))
			{
				//獲取每個詞的分析結果				
				Map mapWord = new HashMap();//建立一個map物件,用於儲存當前詞的解析結果
				mapWord.put("id", id);// 新增id值
				mapWord.put("cont", token.get(TextAnnotation.class));//新增詞內容
				mapWord.put("pos", token.get(PartOfSpeechAnnotation.class));//新增詞性標註值
				mapWord.put("ner", token.get(NamedEntityTagAnnotation.class));//新增實體識別值
				mapWord.put("lemma", token.get(LemmaAnnotation.class));//新增詞原型
				mapWord.put("charBegin",token.get(CharacterOffsetBeginAnnotation.class));//新增詞在句子中的起始位置
				mapWord.put("charEnd",token.get(CharacterOffsetEndAnnotation.class));//新增詞在句子中的結束位置
				
				//查詢每個詞對應的依存關係。由於原始的解析結果中,依存關係是單獨地集中在另一個字串變數中的,形如: 依存關係名(被依賴詞-被依賴詞id,依賴詞-依賴詞id)\n 依存關係名(被依賴詞-被依賴詞id,依賴詞-依賴詞id)\n......需要對其進行解析,這裡採用的方法是依據\n進行分割,然後再用正則表示式進行匹配,來逐一獲取每一個詞的依賴詞和依存關係名
				int flag=0;//設定標誌位,用於儲存當前詞的依存關係是否已經處理過,0未處理,1已處理
				String[] dArray= (dependencies.toString(SemanticGraph.OutputFormat.LIST)).split("\n");//根據\n進行分割,結果儲存為字串陣列
				for (int i=0;i<dArray.length;i++) //遍歷字串陣列
				{
					if(flag==1) //檢查當前詞的依存關係是否已經處理過,如果已處理,則直接退出遍歷過程
						break; 
					ArrayList dc=getDependencyContnet(dArray[i]);//獲取陣列中第i項,並從中獲取依存關係名,被依賴詞id和依賴詞id,放到一個ArrayList中
					if( Integer.parseInt(String.valueOf(dc.get(2)))==id) //如果當前詞id等於當前依存關係中的依賴詞id,則說明找到對應的關係結構
					{
						mapWord.put("relation",dc.get(0));//新增依存關係名
						mapWord.put("parent",dc.get(1));//新增被依賴詞id
						flag=1; // 將當前詞依存關係標誌設為1
						break;//退出遍歷
					}

				}

				jsonSent.add( mapWord );//將上述結果全部新增到當前句中
				id++;//詞id自增
			}
			System.out.println(jsonSent);
			//            // 獲取並列印句法解析樹
			//            Tree tree = sentence.get(TreeAnnotation.class);
			//            System.out.println("\n"+tree.toString());  

			//            // 獲取並列印依存句法的結果
			//			System.out.println("\nDependency Graph:\n " +dependencies.toString(SemanticGraph.OutputFormat.LIST));

			//            // 獲取並列印實體指代結果
			//            Map<Integer, CorefChain> graph =  document.get(CorefChainAnnotation.class);
			//    	    System.out.println(graph);
		}
	}

	//解析依存關係值的方法。如,從root(abc-1, efg-3)中獲取一個ArrayList,值為[root,1,3]
	public static ArrayList getDependencyContnet(String sent)
	{
		String str=sent;
		ArrayList result=new ArrayList();
		String patternName="(.*)\\(";
		String patternGid="\\(.*-([0-9]*)\\,";
		String patternDid=".*-([0-9]*)\\)";
		Pattern r = Pattern.compile(patternName);
		Matcher m = r.matcher(str);
		if(m.find())
		{
			result.add(m.group(1));
		}
		r=Pattern.compile(patternGid);
		m = r.matcher(str);
		if(m.find())
		{
			result.add(m.group(1));
		}
		r=Pattern.compile(patternDid);
		m = r.matcher(str);
		if(m.find())
		{
			result.add(m.group(1));
		}
		return (result);
	}
}

以“Beijing is the capital of China.”為例,結果為:
[{"id":1,"lemma":"Beijing","relation":"nsubj","parent":"4","ner":"LOCATION","charEnd":7,"cont":"Beijing","charBegin":0,"pos":"NNP"},{"id":2,"lemma":"be","relation":"cop","parent":"4","ner":"O","charEnd":10,"cont":"is","charBegin":8,"pos":"VBZ"},{"id":3,"lemma":"the","relation":"det","parent":"4","ner":"O","charEnd":14,"cont":"the","charBegin":11,"pos":"DT"},{"id":4,"lemma":"capital","relation":"root","parent":"0","ner":"O","charEnd":22,"cont":"capital","charBegin":15,"pos":"NN"},{"id":5,"lemma":"of","ner":"O","charEnd":25,"cont":"of","charBegin":23,"pos":"IN"},{"id":6,"lemma":"China","relation":"prep_of","parent":"4","ner":"LOCATION","charEnd":31,"cont":"China","charBegin":26,"pos":"NNP"},{"id":7,"lemma":".","ner":"O","charEnd":32,"cont":".","charBegin":31,"pos":"."}]