1. 程式人生 > >lucene+ikanalyzer實現中文同義詞搜尋

lucene+ikanalyzer實現中文同義詞搜尋

lucene實現索引的建立與檢索;ikanalyzer實現對中文的分詞;光到這裡已經能夠實現中文的檢索了,但是光這樣還不夠,很多專案中的檢索,應該還能夠對同義詞進行處理,比如索引庫中有“計算機”,“電腦”這樣的詞條,搜尋“筆記本”應該也能把“計算機”,“電腦”這樣的詞條匹配出來,這就涉及到對同義詞的索引檢索了。

兩種方案:

1、在建立索引時,拆詞建索引時就把同義詞考慮進去,將同義詞的詞條加入到索引中,然後檢索時,直接根據輸入拆詞來檢索

2、在建立索引時,不對同義詞進行任何處理,在檢索時,先拆詞,針對拆分出來的詞元(呵呵,自創的稱呼)也即關鍵字,進行同義詞匹配,把匹配好的同義詞拼成一個新的關鍵字,搜尋索引時根據此關鍵字來進行檢索。

個人覺得,方案二更優於方案一,理由如下:在建立索引時,就處理同義詞,一方面會增加索引庫的容量,導致索引效率的降低;其次,如果後期對同義詞進行了擴充套件,比如原來,一個單詞有2個同義詞,後面增加到3個,就需要對索引進行重建了,比較麻煩!

大致程式碼如下:

lucene版本:4.10.3,ikanalyzer:IKAnalyzer2012_hf.jar

lucene每個版本變化貌似蠻大啊,方法之類的都改了好多了,不知道大家有這種感覺沒

建立索引:

/** 
	* MyIndexer.java 
	* V1.0 
	* 2015-1-28-下午8:53:37 
	* Copyright (c) 宜昌***有限公司-版權所有 
	*/
package com.x.same;

import java.io.File;
import java.io.IOException;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.TextField;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.MergePolicy.OneMerge;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.lionsoul.jcseg.analyzer.JcsegAnalyzer4X;
import org.lionsoul.jcseg.core.JcsegTaskConfig;
import org.wltea.analyzer.lucene.IKAnalyzer;

/** 
 * 此類描述的是:
 * @author yax 2015-1-28 下午8:53:37 
 * @version v1.0 
 */
public class MyIndexer {
	
	public static void createIndex(String indexPath) throws IOException{
		Directory directory = FSDirectory.open(new File(indexPath));
		Analyzer analyzer = new IKAnalyzer();
		
//		IKAnalyzer analyzer = new IKAnalyzer();
		IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_3, analyzer);
		IndexWriter indexWriter = new IndexWriter(directory, config);
		Document document1 = new Document();
		document1.add(new TextField("title", "thinkpad超極本筆記本中的戰鬥機", Store.YES));
		indexWriter.addDocument(document1);
		
		Document document2 = new Document();
		document2.add(new TextField("title", "使用者可以在這裡配置自己的擴充套件字典", Store.YES));
		indexWriter.addDocument(document2);
		
		Document document3 = new Document();
		document3.add(new TextField("title", "您可以參考分詞器原始碼", Store.YES));
		indexWriter.addDocument(document3);
		
		Document document4 = new Document();
		document4.add(new TextField("title", "第一臺計算機是美國軍方定製,專門為了計算彈道和射擊特性表面而研製的,承擔開發任務的“莫爾小組”由四位科學家和工程師埃克特、莫克利、戈爾斯坦、博克斯組成。1946年這臺計算機主要元器件採用的是電子管。該機使用了1500" +
												"個繼電器,18800個電子管,佔地170m2,重量重達30多噸,耗電150KW,造價48萬美元。這臺計算機每秒能完成5000次加法運算,400次乘法運算,比當時最快的計算工具快300倍,是繼電器計算機的1000倍、手工計算的20萬倍。" + 
												"用今天的標準看,它是那樣的“笨拙”和“低階”,其功能遠不如一隻掌上可程式設計計算器,但它使科學家們從複雜的計算中解脫出來,它的誕生標誌著人類進入了一個嶄新的資訊革命時代。", Store.YES));
		indexWriter.addDocument(document4);
		indexWriter.close();
	}

}
同義詞處理工具類:
/** 
	* AnalyzerUtil.java 
	* V1.0 
	* 2015-1-28-下午8:42:24 
	* Copyright (c) 宜昌**有限公司-版權所有 
	*/
package com.x.same;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
import org.apache.lucene.analysis.synonym.SynonymFilterFactory;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.util.FilesystemResourceLoader;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;
import org.wltea.analyzer.lucene.IKAnalyzer;

/** 
 * 此類描述的是:
 * @author yax 2015-1-28 下午8:42:24 
 * @version v1.0 
 */
public class AnalyzerUtil {
	
	/**
	 * 
	     * 此方法描述的是:進行中文拆分
	 */
	public static String analyzeChinese(String input, boolean userSmart) throws IOException{
		StringBuffer sb = new StringBuffer();
        StringReader reader = new StringReader(input.trim());
        IKSegmenter ikSeg = new IKSegmenter(reader, userSmart);// true 用智慧分詞 ,false細粒度
        for (Lexeme lexeme = ikSeg.next(); lexeme != null; lexeme = ikSeg.next()) {
        	sb.append(lexeme.getLexemeText()).append(" ");
        }
        return sb.toString();
	}
	
	/**
	 * 
	     * 此方法描述的是:針對上面方法拆分後的片語進行同義詞匹配,返回TokenStream
	 */
	public static TokenStream convertSynonym(String input) throws IOException{
        Version ver = Version.LUCENE_4_10_3;
        Map<String, String> filterArgs = new HashMap<String, String>();
        filterArgs.put("luceneMatchVersion", ver.toString());
        filterArgs.put("synonyms", "config/synonyms.txt");
        filterArgs.put("expand", "true");
        SynonymFilterFactory factory = new SynonymFilterFactory(filterArgs);
        factory.inform(new FilesystemResourceLoader());
        Analyzer whitespaceAnalyzer = new WhitespaceAnalyzer();
        TokenStream ts = factory.create(whitespaceAnalyzer.tokenStream("someField", input));
        return ts;
	}
	
	/**
	 * 
	     * 此方法描述的是:將tokenstream拼成一個特地格式的字串,交給IndexSearcher來處理
	 */
    public static String displayTokens(TokenStream ts) throws IOException
    {
    	StringBuffer sb = new StringBuffer();
        CharTermAttribute termAttr = ts.addAttribute(CharTermAttribute.class);
        ts.reset();
        while (ts.incrementToken())
        {
            String token = termAttr.toString();
            sb.append(token).append(" ");
            System.out.print(token+"|");
//            System.out.print(offsetAttribute.startOffset() + "-" + offsetAttribute.endOffset() + "[" + token + "] ");
        }
        System.out.println();
        ts.end();
        ts.close();
        return sb.toString();
    }
    
    public static void main(String[] args) {
    	String indexPath = "D:\\search\\test";
    	String input = "超級";
    	System.out.println("**********************");
		try {
			String result = displayTokens(convertSynonym(analyzeChinese(input, true)));
//			MyIndexer.createIndex(indexPath);
			List<String> docs = MySearcher.searchIndex(result, indexPath);
			for (String string : docs) {
				System.out.println(string);
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

檢索索引相關類:
/** 
	* MySearcher.java 
	* V1.0 
	* 2015-1-28-下午9:02:32 
	* Copyright (c) 宜昌**有限公司-版權所有 
	*/
package com.x.same;

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.analysis.core.WhitespaceAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.FSDirectory;
import org.lionsoul.jcseg.analyzer.JcsegAnalyzer4X;
import org.lionsoul.jcseg.core.JcsegTaskConfig;

/** 
 * 此類描述的是:
 * @author yax 2015-1-28 下午9:02:32 
 * @version v1.0 
 */
public class MySearcher {
	
	public static List<String> searchIndex(String keyword, String indexPath) throws IOException, ParseException{
		List<String> result = new ArrayList<>();
		IndexSearcher indexSearcher = null;
		IndexReader indexReader = DirectoryReader.open(FSDirectory.open(new File(indexPath)));
		indexSearcher = new IndexSearcher(indexReader);
		Analyzer analyzer = new WhitespaceAnalyzer();
		
		QueryParser queryParser = new QueryParser("title", analyzer);
		Query query = queryParser.parse(keyword);
		TopDocs td = indexSearcher.search(query, 10);
		for (int i = 0; i < td.totalHits; i++) {
			Document document = indexSearcher.doc(td.scoreDocs[i].doc);
			result.add(document.get("title"));
		}
		return result;
	}

}

同義詞檔案格式:

我,俺,hankcs
似,is,are => 是
好人,好心人,熱心人
超極本,計算機,電腦

第1、3、4行是同義詞,第二行表示對似,is,are進行是的轉換,即糾錯功能

發現了一種更簡潔的做法,即把關鍵詞分詞,轉換同義詞,合併的過程交給一個自定義Analyzer去處理,程式碼如下:

    public class IKSynonymsAnalyzer extends Analyzer {
    @Override
    protected TokenStreamComponents createComponents(String arg0, Reader arg1) {
    Tokenizer token=new IKTokenizer(arg1, false);//開啟智慧切詞
    Map paramsMap=new HashMap();
    paramsMap.put("luceneMatchVersion", "LUCENE_43");
    paramsMap.put("synonyms", "C:\\同義詞\\synonyms.txt");
    SynonymFilterFactory factory=new SynonymFilterFactory(paramsMap);
    FilesystemResourceLoader loader = new FilesystemResourceLoader();
    try {
    factory.inform(loader);
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    return new TokenStreamComponents(token, factory.create(token));
    }

    }

謝謝Spring_LGF給我的啟示,參考地址:http://blog.csdn.net/winnerspring/article/details/37567739

程式碼僅做參考,歡迎大家交流討論指正。

轉載請註明出處

相關推薦

lucene+ikanalyzer實現中文同義詞搜尋

lucene實現索引的建立與檢索;ikanalyzer實現對中文的分詞;光到這裡已經能夠實現中文的檢索了,但是光這樣還不夠,很多專案中的檢索,應該還能夠對同義詞進行處理,比如索引庫中有“計算機”,“電腦”這樣的詞條,搜尋“筆記本”應該也能把“計算機”,“電腦”這樣的詞條匹配

使用IKAnalyzer實現中文分詞&去除中文停用詞

1、簡介:IKAnalyzer是一個開源的,基於java語言開發的輕量級的中文分詞工具包。這裡使用的是IKAnalyzer2012。 2、IK Analyzer 2012特性: (1)採用了特有的“正向迭代最細粒度切分演算法“,支援細粒度和智慧分詞兩種切分模式; (2)在

Sphinx+Mysql+中文分詞安裝-實現中文全文搜尋

1、什麼是SphinxSphinx 是一個在GPLv2 下發布的一個全文檢索引擎,商業授權(例如, 嵌入到其他程式中)需要聯絡我們(Sphinxsearch.com)以獲得商業授權。一般而言,Sphinx是一個獨立的搜尋引擎,意圖為其他應用提供高速、低空間佔用、高結果相關度的

IKAnalyzer結合Lucene實現中文分詞

++ reset utf-8 incr ttr 中文分詞 擴展 沒有 font 1、基本介紹   隨著分詞在信息檢索領域應用的越來越廣泛,分詞這門技術對大家並不陌生。對於英文分詞處理相對簡單,經過拆分單詞、排斥停止詞、提取詞幹的過程基本就能實現英文分詞,單對於中文分詞而言,

Lucene實現自定義中文同義詞分詞器

----------------------------------------------------------lucene的分詞_中文分詞介紹---------------------------------------------------------- Paod

elasticsearch ik分詞實現 中文、拼音、同義詞搜尋

EasticSearch版本:1.5.2   2.1、在elasticsearch的plugins目錄下,新建analysis-pinyin資料夾,解壓上述壓縮包,將裡面的    放到analys

Lucene筆記37-Lucene如何通過NRTManager和SearchManager實現近實時搜尋

一、思路分析 如何實現近實時搜尋呢?每次更新完索引都commit?那恐怕太浪費資源了,當資料量非常龐大的時候,幾乎不可能。這裡有兩種方案。 使用SearchManager來管理IndexSearcher物件,當發現索引更新之後,searchManager會呼叫maybeReopen

SpringBoot整合Elasticsearch 進階,實現[中文、拼音、繁簡體轉換]高階搜尋

Elasticsearch 分詞 分詞分為讀時分詞和寫時分詞。 讀時分詞發生在使用者查詢時,ES 會即時地對使用者輸入的關鍵詞進行分詞,分詞結果只存在記憶體中,當查詢結束時,分詞結果也會隨即消失。而寫時分詞發生在文件寫入時,ES 會對文件進行分詞後,將結果存入倒排索引,該部分最終會以

使用 Elasticsearch ik分詞實現同義詞搜尋

1、首先需要安裝好Elasticsearch 和elasticsearch-analysis-ik分詞器 2、配置ik同義詞 Elasticsearch 自帶一個名為 synonym 的同義詞 filter。為了能讓 IK 和 synonym 同時工作,我們需要定義新的

Elasticsearch1.x 拼音分詞實現全拼首字母中文混合搜尋

一、外掛簡介 elasticsearch-analysis-lc-pinyin是一款elasticsearch拼音分詞外掛,可以支援按照全拼、首字母,中文混合搜尋。 首先舉個栗子說明下,我們在淘寶搜尋框中輸入“jianpan” 可以搜尋到關鍵字包含“鍵盤”的商品。不僅僅輸入

ElasticSearch 中文同義詞實現

1:elasticserach.yml 最後一行新增如下內容(該檔案位於elasticsearch-x.x.x/config目錄下): index.analysis.analyzer.default.type: ik 2:在elasticsearch-x

Lucene實現中文分詞

在之前的文章中已經介紹過Lucene了,這裡就不多做介紹。一、中文分詞的原理中文分詞是將一個漢字序列切分為一個一個單獨的詞。分詞就是講連續的字序列安裝一定的規範重新組合成詞序列的過程。隨著機器學習的發展,很多分詞的方法都已經被科研人員實現,也越來越精確。分詞的精確性一定程度上

Elasticsearch5.6搭建及拼音中文混合搜尋實現

功能 分散式的搜尋引擎和資料分析引擎 全文檢索,結構化檢索,資料分析 對海量資料進行近實時的處理 環境搭建 從官網下載壓縮包 elasticsearch-5.6.1.tar.gz; 解

利用UITextField自定義搜尋欄,實現中文輸入過程中字母的搜尋功能

當我們需要搜尋功能時,我們首先想到的肯定是searchBar(當然我還只是個新手),但當我們需要在中文輸入過程中搜索字母的時候時,searchBar就不好用了,只有當文字展示在searchBar上時,才會觸發textDidChange的代理方法。 這時可以用U

mysql利用資料庫函式實現用拼音搜尋中文實現

原文地址 1、建立表: CREATE TABLE IF NOT EXISTS `t_base_pinyin` ( `pin_yin_` VARCHAR (255) CHARACTER SET gbk NOT NULL, `code_` INT (11) NOT NU

php實現中文反轉字符串的方法

str1 單個 head 共和國 list har 字符串 string text 1 <?php 2 3 header("content-type:text/html;charset=utf-8"); 4 /** 5 此函數的作用是反轉中文字符串

簡單測試--C#實現中文漢字轉拼音首字母

esp chart htm foreach ext ads linq 類庫 play 第一種: 這個是自己寫的比較簡單的實現方法,要做漢字轉拼音首字母,首先應該有一個存儲首字母的數組,然後將要轉拼音碼的漢字與每個首字母開頭的第一個漢字即“最小”的漢字作比較,這裏的最小指的是

MySQL實現中文拼音排序

例如 assets mysql edas 進行 解決 fix sel from MySQL下新建一個表,默認采用utf8字符集,中文不能直接按照拼音進行排序。 例如以下語句: SELECT * FROM `tb_fixedassets` order by C_FANAME

pdfmake實現中文支持,解決中文亂碼問題

亂碼 build cnblogs js模塊 fonts字體 修改配置 打開 命令 覆蓋 引言:當初自己為了在項目中bootstrap-table中實現導出pdf,使用的pdfmake,但是pdfmake默認使用的不是中文字體,實現pdfmake使用中文字體主要就是編譯新的v

Sphinx + Coreseek 實現中文分詞搜索

addclass trac 無法連接到 繼續 記錄 warning php接口 整數 href Sphinx + Coreseek 實現中文分詞搜索 Sphinx Coreseek 實現中文分詞搜索 全文檢索 1 全文檢索 vs 數據庫 2