Lucene學習——IKAnalyzer中文分詞(二)
阿新 • • 發佈:2019-02-19
一、環境
1、平臺:MyEclipse8.5/JDK1.5
2、框架:Lucene3.6.1/IKAnalyzer2012/htmlparser
二、目標
2、試圖發現些什麼
三、開發除錯
1、改寫原有的搜尋引擎程式,利用IKAnalyzer使之支援中文分詞,程式碼如下
package org.cyxl.lucene.test; 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.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.index.IndexWriterConfig.OpenMode; import org.apache.lucene.queryParser.ParseException; import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.Searcher; import org.apache.lucene.search.TopScoreDocCollector; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import org.apache.lucene.util.Version; import org.htmlparser.NodeFilter; import org.htmlparser.Parser; import org.htmlparser.beans.StringBean; import org.htmlparser.filters.NodeClassFilter; import org.htmlparser.tags.LinkTag; import org.htmlparser.util.NodeList; import org.htmlparser.util.ParserException; import org.htmlparser.visitors.HtmlPage; import org.wltea.analyzer.lucene.IKAnalyzer; public class ParseURL { //索引目錄 private static final String INDEX_DIR = "myindex"; //已經存在的url列表 private static List<String> urls=new ArrayList<String>(); /** * 索引器,對目標url建立索引 * @param url 目標網址 * @throws IOException * @throws ParserException */ @SuppressWarnings("deprecation") private static void indexer(String url) throws IOException, ParserException { //儲存索引的目錄 File indexDir = new File(INDEX_DIR); //目錄不存在,建立該目錄 if (!indexDir.exists()) { indexDir.mkdir(); } //獲取網頁純文字 String content = getText(url); //獲取網頁標題 String title = getTitle(url); System.out.println("title:" + title); if(title==null || content==null || content.trim().equals("")) { return; } // System.out.println("content:" + content); // URL path=new URL(url); // InputStream stream=path.openStream(); // // Reader reader=new InputStreamReader(stream); // Reader reader=new InputStreamReader(new ByteArrayInputStream(content.getBytes())); // Reader reader2=new InputStreamReader(new ByteArrayInputStream(title.getBytes())); Document doc = new Document(); //加入url域 doc.add(new Field("url", url, Field.Store.YES, Field.Index.NOT_ANALYZED)); //加入標題域 doc.add(new Field("title", title, Field.Store.YES, Field.Index.ANALYZED)); // doc.add(new Field("title",reader2)); //Index.ANALYZED分詞後構建索引 //加入內容域 doc.add(new Field("content", content, Field.Store.YES, Field.Index.ANALYZED)); // doc.add(new Field("content",reader)); //建立IKAnalyzer中文分詞物件 Analyzer analyzer=new IKAnalyzer(); //索引目錄 Directory dir=FSDirectory.open(indexDir); //配置IndexWriterConfig IndexWriterConfig iwConfig = new IndexWriterConfig(Version.LUCENE_36 , analyzer); iwConfig.setOpenMode(OpenMode.CREATE_OR_APPEND); //建立寫索引物件 IndexWriter writer = new IndexWriter(dir,iwConfig); //寫入文件 writer.addDocument(doc); //關閉 writer.close(); //建立了索引的網址加入到已經存在的網址列表中 urls.add(url); } /** * 搜尋器,根據輸入的文字去搜索 * @param words 輸入的文字 * @param field 搜尋的域 * @throws CorruptIndexException * @throws IOException * @throws ParseException */ @SuppressWarnings("deprecation") private static void searcher(String words,String field) throws CorruptIndexException, IOException, ParseException { File indexDir = new File(INDEX_DIR); //索引目錄 Directory dir=FSDirectory.open(indexDir); //根據索引目錄建立讀索引物件 IndexReader reader = IndexReader.open(dir); //搜尋物件建立 IndexSearcher searcher = new IndexSearcher(reader); //IKAnalyzer中文分詞 Analyzer analyzer = new IKAnalyzer(); //建立查詢解析物件 QueryParser parser = new QueryParser(Version.LUCENE_36,field, analyzer); parser.setDefaultOperator(QueryParser.AND_OPERATOR); //根據域和目標搜尋文字建立查詢器 Query query = parser.parse(words); System.out.println("Searching for: " + query.toString(field)); //對結果進行相似度打分排序 TopScoreDocCollector collector = TopScoreDocCollector.create(5 * 10,false); searcher.search(query, collector); //獲取結果 ScoreDoc[] hits = collector.topDocs().scoreDocs; int numTotalHits = collector.getTotalHits(); System.out.println(numTotalHits + " total matching pages"); //顯示搜尋結果 for (int i = 0; i < hits.length; i++) { Document doc = searcher.doc(hits[i].doc); String url = doc.get("url"); String title=doc.get("title"); String content=doc.get("content"); System.out.println((i + 1) + "." + title); System.out.println("-----------------------------------"); System.out.println(content.substring(0,100)+"......"); System.out.println("-----------------------------------"); System.out.println(url); System.out.println(); } } /** * 收入網站 * @param url 網站首頁url,也可以為網站地圖url * @throws ParserException * @throws IOException * @throws ParseException */ private static void addSite(String url) throws ParserException, IOException, ParseException { long start=System.currentTimeMillis(); System.out.println("start add..."); //獲取目標網頁的所有連結 List<String> links = getLinks(url); System.out.println("url count:"+links.size()); for(int i=0;i<links.size();i++) { String link=links.get(i); System.out.println((i+1)+"."+link); if(!urls.contains(link)) { //對未建立過索引的網頁建立索引 indexer(link); } else { System.out.println("["+link+"] exist"); } } System.out.println("end..."); long end=System.currentTimeMillis(); System.out.println("cost "+(end-start)/1000+" seconds"); } /** * 獲取網頁純文字 * @param url 目標網址 * @return * @throws ParserException */ private static String getText(String url) throws ParserException { StringBean sb = new StringBean(); // 設定不需要得到頁面所包含的連結資訊 sb.setLinks(false); // 設定將不間斷空格由正規空格所替代 sb.setReplaceNonBreakingSpaces(true); // 設定將一序列空格由一個單一空格所代替 sb.setCollapse(true); // 傳入要解析的URL sb.setURL(url); // 返回解析後的網頁純文字資訊 String content = sb.getStrings(); // System.out.println(content); return content; } /** * 獲取網頁標題 * @param path * @return * @throws IOException * @throws ParserException */ private static String getTitle(String path) throws IOException, ParserException { String title = ""; try { Parser parser=new Parser(path); HtmlPage page = new HtmlPage(parser); parser.visitAllNodesWith(page); title=page.getTitle(); } catch (Exception e) { // TODO Auto-generated catch block //e.printStackTrace(); title = "no title"; } return title.trim(); } /** * 獲取網頁中所有的連結 * @param url * @return * @throws ParserException */ private static List<String> getLinks(String url) throws ParserException { List<String> links=new ArrayList<String>(); //建立連結節點的過濾器 NodeFilter filter = new NodeClassFilter(LinkTag.class); Parser parser = new Parser(); parser.setURL(url); //設定目標網頁的編碼方式 //parser.setEncoding("utf-8"); //因為有些時候不清楚目標網頁的編碼方式,這裡我們採用指定一 //個編碼集合,然後通過試探的方式得到目標網頁的編碼方式 parser.setEncoding(CharsetAutoSwitch.dectedEncode(url)); NodeList list = parser.extractAllNodesThatMatch(filter); for (int i = 0; i < list.size(); i++) { LinkTag node = (LinkTag) list.elementAt(i); //獲取連結的目標網址 String link=node.extractLink(); if(link!=null && !link.trim().equals("") && !link.equals("#")) { //將目標網址加入到該頁面的所有網址列表中 links.add(link); } } return links; } public static void main(String[] args) throws IOException, ParseException, InterruptedException, ParserException { String url = "http://www.csdn.net/"; //收錄網站 addSite(url); //搜有標題帶有“搜尋引擎”字眼的網頁 searcher("搜尋引擎","title"); } }
2、測試結果,如下
載入擴充套件詞典:ext.dic 載入擴充套件停止詞典:stopword.dic 載入擴充套件停止詞典:chinese_stopword.dic Searching for: +搜尋引擎 +搜尋 +索引 +引擎 3 total matching pages 1.搜尋引擎-CSDN.NET ----------------------------------- 搜尋引擎-CSDN.NET 業界 移動開發 雲端計算 軟體研發 專題 程式設計師雜誌 產品 創業 職場 人物 設計 開源 iOS Android WindowsPhone H...... ----------------------------------- http://www.csdn.net/article/tag/%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E 2.充分使用HTML5特性進行搜尋引擎優化(SEO) | Intel? Developer Zone ----------------------------------- 充分使用HTML5特性進行搜尋引擎優化(SEO) | Intel? Developer Zone 跳轉到主要內容 Intel? Developer Zone 社群 按行業焦點選擇 遊戲和媒體...... ----------------------------------- http://g.csdn.net/5231640 3.龐果網-Pongo.cn -IT網際網路計算機通訊領域職位搜尋引擎 ----------------------------------- 龐果網-Pongo.cn -IT網際網路計算機通訊領域職位搜尋引擎 企業使用者 登入 CSDN會員可直接登入 帳 號 密 碼 記住我 忘記密碼 ").append(" 我的pongo |"...... ----------------------------------- http://www.pongo.cn
3、具體的程式碼解釋根據程式碼註釋進行理解
四、總結
1、由於IKAnalyzer2012只支援Lucene3.3以上版本,所以我們這裡採用Lucene3.6.1,和之前的方式稍微有些差別,具體參見程式碼和註釋
2、該程式已經支援了中文站點的收錄的搜尋,以初步達成了中文分詞和搜尋的目的
3、試圖發現些什麼,主要有一下幾點
1)ext.dic自己的詞典如何擴充套件。比如我們這裡收錄了CSDN網站,由於它是一個以程式開發為主的部落格站點,所以我們搜尋“搜尋引擎”時,應該將其看成一個詞,而不是分成“搜尋引擎 +搜尋 +索引 +引擎”,還有“儲存過程”等,我們可以將其加入到擴充套件詞典中。這裡主要跟專案的業務關係比較大,所以應該根據專案來確定擴充套件詞典
2)chinese_stopword.dic的擴充套件也可以根據專案業務來擴充套件,但這個相對固定和簡單些
3)對於網站的收錄,這裡只做了簡單的首頁中連結的挖掘。實際收錄時可以更加深層次的挖掘出所有該站點的頁面。但某頁面如何判定是否屬於該站點對我目前來說是一個難點,希望知者不吝賜教
4)該程式只是個簡單的測試雛形,如何使之有用值得我去思考