摘要:全文檢索概述數(shù)據(jù)分類結(jié)構(gòu)化數(shù)據(jù)具有固定格式或者長(zhǎng)度有限的數(shù)據(jù),例如數(shù)據(jù)庫(kù)中的表。語(yǔ)句非結(jié)構(gòu)化數(shù)據(jù)與結(jié)構(gòu)化數(shù)據(jù)對(duì)立,例如郵件網(wǎng)頁(yè)文檔。
全文檢索概述 數(shù)據(jù)分類
結(jié)構(gòu)化數(shù)據(jù):具有固定格式或者長(zhǎng)度有限的數(shù)據(jù),例如數(shù)據(jù)庫(kù)中的表?!維QL語(yǔ)句】
非結(jié)構(gòu)化數(shù)據(jù):與結(jié)構(gòu)化數(shù)據(jù)對(duì)立,例如:郵件、網(wǎng)頁(yè)、word文檔。【數(shù)據(jù)掃描、全文檢索】
半結(jié)構(gòu)化數(shù)據(jù):介于兩者之間,例如xml或者json格式的數(shù)據(jù)。
全文檢索過程反向索引(倒排表):由字符串到文件的映射是文件到字符串映射的反向過程。
索引創(chuàng)建 索引檢索 Lucene數(shù)學(xué)模型 文檔、域、詞元文檔是Lucene搜索和索引的原子單位,文檔為包含一個(gè)或者多個(gè)域的容器,而域則是依次包含“真正的”被搜索的內(nèi)容,域值通過分詞技術(shù)處理,得到多個(gè)詞元。
For Example,一篇小說(斗破蒼穹)信息可以稱為一個(gè)文檔,小說信息又包含多個(gè)域,例如:標(biāo)題(斗破蒼穹)、作者、簡(jiǎn)介、最后更新時(shí)間等等,對(duì)標(biāo)題這個(gè)域采用分詞技術(shù)又可以得到一個(gè)或者多個(gè)詞元(斗、破、蒼、穹)。
詞元權(quán)重計(jì)算Term Frequency(tf):此term在文檔中出現(xiàn)的次數(shù),tf越大則該詞元越重要。
Document Frequency(df):有多少文檔包含此term,df越大該詞元越不重要。
空間向量模型如下:
計(jì)算夾角的余弦值,夾角越小,余弦值越大,分值越大,從而相關(guān)性越大。
Lucene文件結(jié)構(gòu) 層次結(jié)構(gòu)index:一個(gè)索引存放在一個(gè)目錄中;
segment:一個(gè)索引中可以有多個(gè)段,段與段之間是獨(dú)立的,添加新的文檔可能產(chǎn)生新段,不同的段可以合并成一個(gè)新段;
document:文檔是創(chuàng)建索引的基本單位,不同的文檔保存在不同的段中,一個(gè)段可以包含多個(gè)文檔;
field:域,一個(gè)文檔包含不同類型的信息,可以拆分開索引;
term:詞,索引的最小單位,是經(jīng)過詞法分析和語(yǔ)言處理后的數(shù)據(jù)。
正向信息按照層次依次保存了從索引到詞的包含關(guān)系:index-->segment-->document-->field-->term。
反向信息反向信息保存了詞典的倒排表映射:term-->document
配置Lucene開發(fā)環(huán)境Lucene是ASF的開源項(xiàng)目,最新版本是5.2.1,但是鑒于網(wǎng)絡(luò)上大多數(shù)教程使用的是Lucene 4,在本文中使用的版本是Lucene 4.3.1,下載解壓,到對(duì)應(yīng)目錄找到以下的jar包并添加到構(gòu)建路徑中。
如果使用maven其maven依賴如下:
Lucene常用功能介紹 索引創(chuàng)建 創(chuàng)建索的關(guān)鍵類org.apache.lucene lucene-core 4.3.1 org.apache.lucene lucene-queryparser 4.3.1 org.apache.lucene lucene-queries 4.3.1 org.apache.lucene lucene-highlighter 4.3.1 org.apache.lucene lucene-analyzers-smartcn 4.3.1 org.apache.lucene lucene-analyzers-common 4.3.1
創(chuàng)建索引的示例代碼:
/** * 索引創(chuàng)建 */ @Test public void createIndex() { // 創(chuàng)建一個(gè)分詞器(指定Lucene版本) Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_43); // IndexWriter配置信息(指定Lucene版本和分詞器) IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_43, analyzer); // 設(shè)置索引的打開方式 indexWriterConfig.setOpenMode(OpenMode.CREATE_OR_APPEND); // 創(chuàng)建Directory對(duì)象和IndexWriter對(duì)象 Directory directory = null; IndexWriter indexWriter = null; try { directory = FSDirectory.open(new File("Lucene_index/test")); // 檢查Directory對(duì)象是否處于鎖定狀態(tài)(如果鎖定則進(jìn)行解鎖) if (IndexWriter.isLocked(directory)) { IndexWriter.unlock(directory); } indexWriter = new IndexWriter(directory, indexWriterConfig); } catch (IOException e) { e.printStackTrace(); } // 創(chuàng)建測(cè)試文檔并為其添加域 Document doc1 = new Document(); doc1.add(new StringField("id", "abcde", Store.YES)); // 添加一個(gè)id域,域值為abcde doc1.add(new TextField("content", "使用Lucene實(shí)現(xiàn)全文檢索", Store.YES)); // 文本域 doc1.add(new IntField("num", 1, Store.YES)); // 添加數(shù)值域 // 將文檔寫入索引 try { indexWriter.addDocument(doc1); } catch (IOException e) { e.printStackTrace(); } Document doc2 = new Document(); doc2.add(new StringField("id", "yes", Store.YES)); doc2.add(new TextField("content", "Docker容器技術(shù)簡(jiǎn)介", Store.YES)); doc2.add(new IntField("num", 2, Store.YES)); try { indexWriter.addDocument(doc2); } catch (IOException e) { e.printStackTrace(); } // 將IndexWriter提交 try { indexWriter.commit(); } catch (IOException e) { e.printStackTrace(); } finally{ try { indexWriter.close(); directory.close(); } catch (IOException e) { e.printStackTrace(); } } }
生成的索引文件如下:
索引檢索 索引檢索關(guān)鍵類利用以下的檢索程序?qū)η懊鎰?chuàng)建的索引進(jìn)行檢索:
/** * 索引檢索 */ @Test public void searchIndex(){ Directory directory = null; DirectoryReader dReader = null; try { directory = FSDirectory.open(new File("Lucene_index/test")); // 索引文件 dReader = DirectoryReader.open(directory); // 讀取索引文件 IndexSearcher searcher = new IndexSearcher(dReader); // 創(chuàng)建IndexSearcher對(duì)象 Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_43); // 指定分詞技術(shù)(標(biāo)準(zhǔn)分詞-與創(chuàng)建索引時(shí)使用的分詞技術(shù)一致) // 創(chuàng)建查詢字符串(指定搜索域和采用的分詞技術(shù)) QueryParser parser = new QueryParser(Version.LUCENE_43, "content", analyzer); Query query = parser.parse("Docker"); // 創(chuàng)建Query對(duì)象(指定搜索詞) // 檢索索引(指定前10條) TopDocs topDocs = searcher.search(query, 10); if (topDocs != null) { System.out.println("符合條件的文檔總數(shù)為:" + topDocs.totalHits); for (int i = 0; i < topDocs.scoreDocs.length; i++) { Document doc = searcher.doc(topDocs.scoreDocs[i].doc); System.out.println("id = " + doc.get("id") + ",content = " + doc.get("content") + ",num = " + doc.get("num")); } } } catch (IOException e) { e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); } finally{ try { dReader.close(); directory.close(); } catch (IOException e) { e.printStackTrace(); } } }
運(yùn)行結(jié)果:
Lucene分詞器 常見分詞器其中IKAnalyzer需要下載專門的jar包
/** * 常見分詞器 */ @Test public void testAnalyzer(){ final String str = "利用Lucene 實(shí)現(xiàn)全文檢索"; Analyzer analyzer = null; analyzer = new StandardAnalyzer(Version.LUCENE_43); // 標(biāo)準(zhǔn)分詞 print(analyzer, str); analyzer = new IKAnalyzer(); // 第三方中文分詞 print(analyzer, str); analyzer = new WhitespaceAnalyzer(Version.LUCENE_43); // 空格分詞 print(analyzer, str); analyzer = new SimpleAnalyzer(Version.LUCENE_43); // 簡(jiǎn)單分詞 print(analyzer, str); analyzer = new CJKAnalyzer(Version.LUCENE_43); // 二分法分詞 print(analyzer, str); analyzer = new KeywordAnalyzer(); // 關(guān)鍵字分詞 print(analyzer, str); analyzer = new StopAnalyzer(Version.LUCENE_43); //被忽略詞分詞器 print(analyzer, str); } /** * 該方法用于打印分詞器及其分詞結(jié)果 * @param analyzer 分詞器 * @param str 需要分詞的字符串 */ public void print(Analyzer analyzer,String str){ StringReader stringReader = new StringReader(str); try { TokenStream tokenStream = analyzer.tokenStream("", stringReader); // 分詞 tokenStream.reset(); CharTermAttribute term = tokenStream.getAttribute(CharTermAttribute.class); // 獲取分詞結(jié)果的CharTermAttribute System.out.println("分詞技術(shù):" + analyzer.getClass()); while (tokenStream.incrementToken()) { System.out.print(term.toString() + "|"); } System.out.println(); } catch (IOException e) { e.printStackTrace(); } }
運(yùn)行結(jié)果:
Query創(chuàng)建/** * 創(chuàng)建Query */ @Test public void createQuery(){ String key = "JAVA EE Lucene案例開發(fā)"; String field = "name"; String[] fields = {"name","content"}; Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_43); // 分詞器 // 單域查詢 QueryParser parser1 = new QueryParser(Version.LUCENE_43, field, analyzer); Query query1 = null; try { query1 = parser1.parse(key); // 使用QueryParser創(chuàng)建Query } catch (ParseException e) { e.printStackTrace(); } System.out.println(QueryParser.class + query1.toString()); // 多域查詢 MultiFieldQueryParser parser2 = new MultiFieldQueryParser(Version.LUCENE_43, fields, analyzer); try { query1 = parser2.parse(key); } catch (ParseException e) { e.printStackTrace(); } System.out.println(QueryParser.class + query1.toString()); // 短語(yǔ)查詢 query1 = new TermQuery(new Term(field, key)); System.out.println(TermQuery.class + query1.toString()); // 前綴查詢 query1 = new PrefixQuery(new Term(field, key)); System.out.println(PrefixQuery.class + query1.toString()); // 短語(yǔ)查詢 PhraseQuery query2 = new PhraseQuery(); query2.setSlop(2); // 設(shè)置短語(yǔ)間的最大距離是2 query2.add(new Term(field, "Lucene")); query2.add(new Term(field, "案例")); System.out.println(PhraseQuery.class + query2.toString()); // 通配符查詢 query1 = new WildcardQuery(new Term(field, "Lucene?")); System.out.println(WildcardQuery.class + query1.toString()); // 字符串范圍搜索 query1 = TermRangeQuery.newStringRange(field, "abc", "azz", false, false); System.out.println(TermRangeQuery.class + query1.toString()); // 布爾條件查詢 BooleanQuery query3 = new BooleanQuery(); query3.add(new TermQuery(new Term(field, "Lucene")),Occur.SHOULD); // 添加條件 query3.add(new TermQuery(new Term(field, "案例")),Occur.MUST); query3.add(new TermQuery(new Term(field, "案例")),Occur.MUST_NOT); System.out.println(BooleanQuery.class + query3.toString()); }
運(yùn)行結(jié)果:
IndexSearcher常用方法檢索關(guān)鍵類
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/64432.html
閱讀 2753·2021-10-11 10:57
閱讀 1585·2021-09-26 09:55
閱讀 1320·2021-09-06 15:11
閱讀 3464·2021-08-26 14:16
閱讀 680·2019-08-30 15:54
閱讀 547·2019-08-30 12:43
閱讀 3304·2019-08-29 16:18
閱讀 2581·2019-08-23 16:14