Lucene AnIKAlyzerを使用した分詞インスタンスおよびIKAnalyzer拡張辞書
シナリオ1:構成ベースの辞書拡張
プロジェクト構造図は以下の通りである: IK分詞器はIKAnalyzerを構成することによってもサポートする.cfg.xmlファイルを使用して、独自の辞書を拡張します.Googleピンイン辞書ダウンロード:http://ishare.iask.sina.com.cn/f/14446921.html?from=like Webプロジェクトのsrcディレクトリの下でIKAnalyzerを作成cfg.xmlファイル、内容は以下の通りです
辞書ファイルの編集と配置分詞器の辞書ファイルフォーマットはBOMのないUTF-8符号化の中国語テキストファイルであり、ファイル拡張子は限定されない.辞書では、中国語の語彙ごとに独立して1行を占め、rのDOS方式で改行する.(注意:BOMのないUTF-8形式が分からない場合は、辞書でUTF-8を使用して保存し、ファイルのヘッダに空の行を追加することを保証してください).分詞器のソースコードorgを参照できます.wltea.analyzer.dicパッケージdicファイル.辞書ファイルは、Javaのリソースパス、つまりClassLoaderがロードできるパスに配置する必要があります.(IKEAnalyzer.cfg.xmlと一緒に置くことをお勧めします).
シナリオ2:APIベースの辞書拡張
IKAnalyzerでの語句に関する操作1.org.wltea.analyzer.cfg 2.org.wltea.analyzer.dic
org.wltea.analyzer.dicの下のDirectoryクラスに関連する方法
LuceneでIKAnalyzer分詞器インスタンスを使用してビジネスエンティティを実証
シミュレーションデータの構築
シミュレーションデータをLuceneで取得する
プログラム実行結果
インデックスが存在するかどうかを判断する方法
付録:IK分詞処理プロセス
IKの全分詞処理過程まず、IKの全分詞処理過程を紹介する.
1.Luceneの分詞ベースクラスはAnalyzerであるため、IKはAnalyzerの実装クラスIKAnalyzerを提供する.まず、IKが最大語長分詞を採用するか、それとも最も細粒度の2つの分詞アルゴリズムを採用するかを識別するパラメータisMaxWordLengthを受信する構造方法があるIKAnalyzerをインスタンス化します.実際の2つのアルゴリズムの実現は,最大語長切断は最細粒度切断の後続処理であり,最細粒度切断結果のフィルタリングであり,最長の分詞結果を選択する.
2.IKAnalyzerクラスはAnalyzerのtokenStreamメソッドを書き換え、このメソッドは2つのパラメータ、field nameと入力ストリームreaderを受信し、filed nameはLuceneの属性列であり、テキストの内容を過剰に処理し、インデックスを作成した後、インデックスに対応する名前であり、データベースのカラム名に似ている.IKは分詞処理のみに関与するためfield nameについては何も処理していないので,ここでは何も議論しない.
3.tokenStreamメソッドは、Luceneがテキスト入力ストリームreaderを分詞処理するときに呼び出され、IKAnalyzerのtokenStreamメソッドには、LuceneのTokenizerクラスを継承するIKTokenizerクラスがインスタンス化されているだけである.テキスト入力ストリームを処理してtoken,すなわちLuceneの最小語元termを生成するincrementTokenメソッドを書き直し,IKではLexemeと呼ぶ.
4.IKtokenizerの構造方法では、IKで最終的に必要とされる分詞類IKSegmentationが実例化されており、主分詞器とも呼ばれる.その構築方法は2つのパラメータ,readerとisMaxWordLengthを受信する.
5.IKsegmentationの構築方法では、主に3つの作業を行い、コンテキストオブジェクトContextを作成し、辞書をロードし、サブ分詞器を作成します.
6.Contexは主に分詞結果セットと分詞処理を記録するカーソル位置である.
7.辞書は一例として作成され、主に量詞辞書、主辞書、停詞辞書がある.辞書は辞書セグメントクラスDictSegmentという辞書コアクラスに格納されている.DictSegmentには静的なストレージ構造charMapがあり、すべての漢字を格納するための共通辞書表であり、keyとvalueは中国語の漢字であり、現在IKのcharMapには約7100以上のキー値ペアがある.また、DictSegmentには、辞書ツリーを格納するための2つの最も重要なデータ構造があり、1つはDictSegmentの配列childrenArrayであり、もう1つはkeyが単一の漢字(各単語の最初の漢字)であり、valueはDictSegmentのHashMap childrenMapである.この2つのデータ構造の2つは、辞書ツリーを格納するために1つを取ります.
8.子分詞器こそ本当の分詞類で、IKには3つの子分詞器、量詞分詞器、CJK分詞器(中国語処理)、停詞分詞器がある.メイン分詞器IKSegmentationは、この3つの分詞器を巡回してテキスト入力ストリームを分詞処理する.
9.IKTokenizerのincrementTokenメソッドは、次の分詞結果を得るためにIKSegmentationのnextメソッドを呼び出します.nextが最初に呼び出されると,テキスト入力ストリームをロードしてbufferに読み込む必要があり,サブ分詞器を巡り,buffer種のテキスト内容を分詞処理し,分詞結果をcontextのlexemeSetに追加する.転送先は出典を明記してください:[http://www.cnblogs.com/dennisit/archive/2013/04/07/3005847.html]
プロジェクト構造図は以下の通りである: IK分詞器はIKAnalyzerを構成することによってもサポートする.cfg.xmlファイルを使用して、独自の辞書を拡張します.Googleピンイン辞書ダウンロード:http://ishare.iask.sina.com.cn/f/14446921.html?from=like Webプロジェクトのsrcディレクトリの下でIKAnalyzerを作成cfg.xmlファイル、内容は以下の通りです
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer </comment>
<!-- -->
<entry key="ext_dict">/dicdata/use.dic.dic;/dicdata/googlepy.dic</entry>
<!-- -->
<entry key="ext_stopwords">/dicdata/ext_stopword.dic</entry>
</properties>
辞書ファイルの編集と配置分詞器の辞書ファイルフォーマットはBOMのないUTF-8符号化の中国語テキストファイルであり、ファイル拡張子は限定されない.辞書では、中国語の語彙ごとに独立して1行を占め、rのDOS方式で改行する.(注意:BOMのないUTF-8形式が分からない場合は、辞書でUTF-8を使用して保存し、ファイルのヘッダに空の行を追加することを保証してください).分詞器のソースコードorgを参照できます.wltea.analyzer.dicパッケージdicファイル.辞書ファイルは、Javaのリソースパス、つまりClassLoaderがロードできるパスに配置する必要があります.(IKEAnalyzer.cfg.xmlと一緒に置くことをお勧めします).
シナリオ2:APIベースの辞書拡張
IKAnalyzerでの語句に関する操作1.org.wltea.analyzer.cfg 2.org.wltea.analyzer.dic
org.wltea.analyzer.cfg Configuration
getExtDictionarys()
getExtStopWordDictionarys()
getMainDictionary()
getQuantifierDicionary()
org.wltea.analyzer.cfg.DefualtConfig Configuration
org.wltea.analyzer.dicの下のDirectoryクラスに関連する方法
public void addWords(java.util.Collection<java.lang.String> words) :words - Collection public void disableWords(java.util.Collection<java.lang.String> words) ( )
LuceneでIKAnalyzer分詞器インスタンスを使用してビジネスエンティティを実証
package com.icrate.service.study.demo; /** * * * @version : 1.0 * * @author : <a href="mailto:[email protected]"> </a> * * @since : 1.0 : 2013-4-7 01:52:49 * * @function: TODO * */
public class Medicine { private Integer id; private String name; private String function; public Medicine() { } public Medicine(Integer id, String name, String function) { super(); this.id = id; this.name = name; this.function = function; } //getter and setter()
public String toString(){ return this.id + "," +this.name + "," + this.function; } }
シミュレーションデータの構築
package com.icrate.service.study.demo; import java.util.ArrayList; import java.util.List; /** * * * @version : 1.0 * * @author : <a href="mailto:[email protected]"> </a> * * @since : 1.0 : 2013-4-7 01:54:34 * * @function: TODO * */
public class DataFactory { private static DataFactory dataFactory = new DataFactory(); private DataFactory(){ } public List<Medicine> getData(){ List<Medicine> list = new ArrayList<Medicine>(); list.add(new Medicine(1," "," : , , , , 。")); list.add(new Medicine(2," "," : , , 。")); list.add(new Medicine(3," "," : 。 , 。")); list.add(new Medicine(4," "," : , , , , 。")); list.add(new Medicine(5," "," : , , , 。")); return list; } public static DataFactory getInstance(){ return dataFactory; } }
シミュレーションデータをLuceneで取得する
package com.icrate.service.study.demo; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.index.Term; import org.apache.lucene.queryParser.MultiFieldQueryParser; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TopDocs; import org.apache.lucene.search.highlight.Formatter; import org.apache.lucene.search.highlight.Fragmenter; import org.apache.lucene.search.highlight.Highlighter; import org.apache.lucene.search.highlight.QueryScorer; import org.apache.lucene.search.highlight.Scorer; import org.apache.lucene.search.highlight.SimpleFragmenter; import org.apache.lucene.search.highlight.SimpleHTMLFormatter; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import org.apache.lucene.util.Version; import org.wltea.analyzer.lucene.IKAnalyzer; /** * * LuenceProcess.java * * @version : 1.1 * * @author : <a href="mailto:[email protected]"> </a> * * @since : 1.0 : Apr 3, 2013 11:48:11 AM * * TODO : Luence IK * */
public class LuceneIKUtil { private Directory directory ; private Analyzer analyzer ; /** * , * @param indexFilePath */
public LuceneIKUtil(String indexFilePath){ try { directory = FSDirectory.open(new File(indexFilePath)); analyzer = new IKAnalyzer(); } catch (IOException e) { e.printStackTrace(); } } /** * , */
public LuceneIKUtil(){ this("/luence/index"); } /** * * Description: * @author [email protected] Apr 3, 2013 * @throws Exception */
public void createIndex()throws Exception{ IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_35,analyzer); IndexWriter indexWriter = new IndexWriter(directory,indexWriterConfig); indexWriter.deleteAll(); List<Medicine> list = DataFactory.getInstance().getData(); for(int i=0; i<list.size(); i++){ Medicine medicine = list.get(i); Document document = addDocument(medicine.getId(), medicine.getName(), medicine.getFunction()); indexWriter.addDocument(document); } indexWriter.close(); } /** * * Description: * @author [email protected] Apr 3, 2013 * @param id * @param title * @param content * @return
*/
public Document addDocument(Integer id, String name, String function){ Document doc = new Document(); //Field.Index.NO //Field.Index.ANALYZED //Field.Index.NOT_ANALYZED
doc.add(new Field("id",String.valueOf(id),Field.Store.YES,Field.Index.NOT_ANALYZED)); doc.add(new Field("name",name,Field.Store.YES,Field.Index.ANALYZED)); doc.add(new Field("function",function,Field.Store.YES,Field.Index.ANALYZED)); return doc; } /** * * Description: * @author [email protected] Apr 3, 2013 * @param id * @param title * @param content */
public void update(Integer id,String title, String content){ try { IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_35,analyzer); IndexWriter indexWriter = new IndexWriter(directory,indexWriterConfig); Document document = addDocument(id, title, content); Term term = new Term("id",String.valueOf(id)); indexWriter.updateDocument(term, document); indexWriter.close(); } catch (Exception e) { e.printStackTrace(); } } /** * * Description: ID * @author [email protected] Apr 3, 2013 * @param id */
public void delete(Integer id){ try { IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_35,analyzer); IndexWriter indexWriter = new IndexWriter(directory,indexWriterConfig); Term term = new Term("id",String.valueOf(id)); indexWriter.deleteDocuments(term); indexWriter.close(); } catch (Exception e) { e.printStackTrace(); } } /** * * Description: * @author [email protected] Apr 3, 2013 * @param where * @param scoreDoc */
public List<Medicine> search(String[] fields,String keyword){ IndexSearcher indexSearcher = null; List<Medicine> result = new ArrayList<Medicine>(); try { // ,
IndexReader indexReader = IndexReader.open(directory,true); indexSearcher = new IndexSearcher(indexReader); MultiFieldQueryParser queryParser =new MultiFieldQueryParser(Version.LUCENE_35, fields,analyzer); Query query = queryParser.parse(keyword); // number
TopDocs topDocs = indexSearcher.search(query, 10); //
int totalCount = topDocs.totalHits; System.out.println(" "+totalCount+" "); //
/* , SimpleHTMLFormatter: 2 1:SimpleHTMLFormatter() . :<B> </B> 2:SimpleHTMLFormatter(String preTag, String postTag). :preTag postTag */ Formatter formatter = new SimpleHTMLFormatter("<font color='red'>","</font>"); /* QueryScorer QueryScorer 。 。QueryScorer ; 、 , (boost factor) 。 QueryScoere , 。 , 、 、 , BoolenaQuery 。 Query QueryScorer , Query.rewrite (IndexReader) Query */ Scorer fragmentScorer = new QueryScorer(query); Highlighter highlighter = new Highlighter(formatter,fragmentScorer); Fragmenter fragmenter = new SimpleFragmenter(100); /* Highlighter Fragmenter 。 SimpleFragmenter , 100 。 。 */ highlighter.setTextFragmenter(fragmenter); ScoreDoc[] scoreDocs = topDocs.scoreDocs; for(ScoreDoc scDoc : scoreDocs){ Document document = indexSearcher.doc(scDoc.doc); Integer id = Integer.parseInt(document.get("id")); String name = document.get("name"); String function = document.get("function"); //float score = scDoc.score; //
String lighterName = highlighter.getBestFragment(analyzer, "name", name); if(null==lighterName){ lighterName = name; } String lighterFunciton = highlighter.getBestFragment(analyzer, "function", function); if(null==lighterFunciton){ lighterFunciton = function; } Medicine medicine = new Medicine(); medicine.setId(id); medicine.setName(lighterName); medicine.setFunction(lighterFunciton); result.add(medicine); } } catch (Exception e) { e.printStackTrace(); }finally{ try { indexSearcher.close(); } catch (IOException e) { e.printStackTrace(); } } return result; } public static void main(String[] args) { LuceneIKUtil luceneProcess = new LuenceIKUtil("F:/index"); try { luceneProcess.createIndex(); } catch (Exception e) { e.printStackTrace(); } //
luceneProcess.update(2, " ", " 。。。"); //
String [] fields = {"name","function"}; List<Medicine> list = luenceProcess.search(fields," "); for(int i=0; i<list.size(); i++){ Medicine medicine = list.get(i); System.out.println("("+medicine.getId()+")"+medicine.getName() + "\t" + medicine.getFunction()); } // //luenceProcess.delete(1);
} }
プログラム実行結果
:/dicdata/use.dic.dic :/dicdata/googlepy.dic :/dicdata/ext_stopword.dic 4 (1) <font color='red'> </font> : <font color='red'> </font> , , , , 。 (4)<font color='red'> </font> : <font color='red'> </font> , , , , 。 (3)<font color='red'> </font> : 。 , 。 (5) <font color='red'> </font> : , , , 。
インデックスが存在するかどうかを判断する方法
/** * * @param indexPath * @return
*/
private boolean isExistIndexFile(String indexPath) throws Exception{ File file = new File(indexPath); if (!file.exists()) { file.mkdirs(); } String indexSufix="/segments.gen"; // segments.gen
File indexFile=new File(indexPath+indexSufix); return indexFile.exists(); }
付録:IK分詞処理プロセス
IKの全分詞処理過程まず、IKの全分詞処理過程を紹介する.
1.Luceneの分詞ベースクラスはAnalyzerであるため、IKはAnalyzerの実装クラスIKAnalyzerを提供する.まず、IKが最大語長分詞を採用するか、それとも最も細粒度の2つの分詞アルゴリズムを採用するかを識別するパラメータisMaxWordLengthを受信する構造方法があるIKAnalyzerをインスタンス化します.実際の2つのアルゴリズムの実現は,最大語長切断は最細粒度切断の後続処理であり,最細粒度切断結果のフィルタリングであり,最長の分詞結果を選択する.
2.IKAnalyzerクラスはAnalyzerのtokenStreamメソッドを書き換え、このメソッドは2つのパラメータ、field nameと入力ストリームreaderを受信し、filed nameはLuceneの属性列であり、テキストの内容を過剰に処理し、インデックスを作成した後、インデックスに対応する名前であり、データベースのカラム名に似ている.IKは分詞処理のみに関与するためfield nameについては何も処理していないので,ここでは何も議論しない.
3.tokenStreamメソッドは、Luceneがテキスト入力ストリームreaderを分詞処理するときに呼び出され、IKAnalyzerのtokenStreamメソッドには、LuceneのTokenizerクラスを継承するIKTokenizerクラスがインスタンス化されているだけである.テキスト入力ストリームを処理してtoken,すなわちLuceneの最小語元termを生成するincrementTokenメソッドを書き直し,IKではLexemeと呼ぶ.
4.IKtokenizerの構造方法では、IKで最終的に必要とされる分詞類IKSegmentationが実例化されており、主分詞器とも呼ばれる.その構築方法は2つのパラメータ,readerとisMaxWordLengthを受信する.
5.IKsegmentationの構築方法では、主に3つの作業を行い、コンテキストオブジェクトContextを作成し、辞書をロードし、サブ分詞器を作成します.
6.Contexは主に分詞結果セットと分詞処理を記録するカーソル位置である.
7.辞書は一例として作成され、主に量詞辞書、主辞書、停詞辞書がある.辞書は辞書セグメントクラスDictSegmentという辞書コアクラスに格納されている.DictSegmentには静的なストレージ構造charMapがあり、すべての漢字を格納するための共通辞書表であり、keyとvalueは中国語の漢字であり、現在IKのcharMapには約7100以上のキー値ペアがある.また、DictSegmentには、辞書ツリーを格納するための2つの最も重要なデータ構造があり、1つはDictSegmentの配列childrenArrayであり、もう1つはkeyが単一の漢字(各単語の最初の漢字)であり、valueはDictSegmentのHashMap childrenMapである.この2つのデータ構造の2つは、辞書ツリーを格納するために1つを取ります.
8.子分詞器こそ本当の分詞類で、IKには3つの子分詞器、量詞分詞器、CJK分詞器(中国語処理)、停詞分詞器がある.メイン分詞器IKSegmentationは、この3つの分詞器を巡回してテキスト入力ストリームを分詞処理する.
9.IKTokenizerのincrementTokenメソッドは、次の分詞結果を得るためにIKSegmentationのnextメソッドを呼び出します.nextが最初に呼び出されると,テキスト入力ストリームをロードしてbufferに読み込む必要があり,サブ分詞器を巡り,buffer種のテキスト内容を分詞処理し,分詞結果をcontextのlexemeSetに追加する.転送先は出典を明記してください:[http://www.cnblogs.com/dennisit/archive/2013/04/07/3005847.html]