數據分類:html
一、結構化數據:格式固定,長度固定,數據類型固定,例如:數據庫中的數據,java
二、非結構化數據:和上面相反,例如:word文檔,pdf文檔,郵件,htmlspring
數據的查詢:數據庫
一、結構化數據的查詢:apache
SQL語句,特色:簡單,速度快windows
二、非結構化數據的查詢:數據結構
把非結構化數據變成結構化數據:先根據空格進行字符串的拆分,獲得一個單詞列表,基於單詞列表建立一個索引(一個爲了提升查詢速度,建立某種數據結構的集合),查詢索引,根據單詞和文檔的對應關係找到文檔列表。工具
應用場景:搜索引擎
一、搜索引擎編碼
二、站內搜索
三、電商搜索
四、只要有搜索的地方
lucene:一個基於java開發全文檢索的工具包
實現全文檢索的流程:
一、建立索引
1·一、得到文檔
原始文檔:要基於那些數據來進行搜索,那麼這些數據就是原始文檔
搜索引擎得到文檔:使用爬蟲得到原始文檔
站內搜索得到文檔:數據庫中的數據
磁盤得到文檔:直接使用io流讀取磁盤上的文檔
1·二、構建文檔對象
對應每一個原始文檔建立一個Document對象,每一個Document對象中包含多個域,域中保存就是原始文檔數據,包含域的名稱和值。
注意:每一個文檔都有一個惟一的編號,就是文檔ID
1·三、分析文檔
分詞的過程:
一、根據空格進行字符串拆分,獲得一個單詞列表
二、把單詞統一轉換成小寫
三、去除標點符號
四、去除停用詞(無心義的詞)
每一個關鍵詞都封裝成一個term對象中,包含關鍵詞所在域和關鍵詞自己。
注意:不一樣的域中拆分出來的相同的關鍵詞是不一樣的term
1·四、建立索引
基於關鍵詞列表建立一個索引,保存到索引庫中。索引庫中包含:索引,document對象,關鍵詞和文檔的對應關係。
補充:經過詞語找文檔,這種索引的結構叫倒排索引結構。
二、查詢索引
2·一、用戶查詢接口
用戶輸入查詢條件的地方,例如:百度的搜索框
2·二、把關鍵詞封裝成一個查詢對象,包含:要查詢的域和要搜索的關鍵詞
2·三、執行查詢,根據要查詢的關鍵詞到對應的域上進行搜索
2·四、渲染結果,根據文檔的id找到文檔對象,對關鍵詞進行處理,最終展現出來
入門代碼:
一、添加MAVEN依賴
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!-- lucene核心庫 --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-core</artifactId> <version>${lunece.version}</version> </dependency> <!-- Lucene的查詢解析器 --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-queryparser</artifactId> <version>${lunece.version}</version> </dependency> <!-- lucene的默認分詞器庫 --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-analyzers-common</artifactId> <version>${lunece.version}</version> </dependency> <!-- lucene的高亮顯示 --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-highlighter</artifactId> <version>${lunece.version}</version> </dependency> </dependencies>
二、代碼建立索引
public void createIndex() throws Exception{ File file = new File("./index"); if (!file.exists()){ file.mkdirs(); } /* Directory directory = new RAMDirectory();//把索引庫保存到內存中,不推薦 */ //建立一個Director對象,指定索引庫保存的位置 Directory directory = FSDirectory.open(file.toPath()); //基於Direcotry對象建立一個indexWriter對象 IndexWriter indexWriter = new IndexWriter(directory,new IndexWriterConfig()); //讀取磁盤上的文件,對應每一個文件建立一個文檔對象 File orgfile = new File(""); File[] files = orgfile.listFiles(); for (File f : files){ //取文件名 String filename = f.getName(); //文件的路徑 String filepath = f.getPath(); //文件的內容 String fileContent = FileUtils.readFileToString(f, "utf-8"); //文件的大小 long filesize = FileUtils.sizeOfDirectory(f); //建立field //參數1:域的名稱,參數2:域的內容,參數3:是否存儲 Field fieldName = new TextField("name",filename,Field.Store.YES); Field fieldPath = new TextField("path",filepath,Field.Store.YES); Field fieldContent = new TextField("content",fileContent,Field.Store.YES); Field fieldsize = new TextField("size",filesize+"",Field.Store.YES); //建立文檔對象 Document document = new Document(); //向文檔對象中添加域 document.add(fieldName); document.add(fieldPath); document.add(fieldContent); document.add(fieldsize); //把文檔對象寫入索引庫 indexWriter.addDocument(document); } //關閉indexwriter對象 indexWriter.close(); }
三、索引庫搜索
public void searchIndex()throws Exception{ //建立一個Director對象,指定索引庫的位置 Directory directory=FSDirectory.open(new File("./index").toPath()); //建立一個indexReader對象 IndexReader indexReader = DirectoryReader.open(directory); //建立一個IndexSearch對象,構造方法中的參數indexReader對象 IndexSearcher indexSearcher = new IndexSearcher(indexReader); //建立一個Query對象,TermQuery Query query = new TermQuery(new Term("content","spring")); //執行查詢,獲得一個TopDocs對象 //參數1:查詢對象,參數2:查詢結果返回的最大記錄數 TopDocs topDocs = indexSearcher.search(query, 10); //取查詢結果的總記錄數 System.out.println(topDocs.totalHits); //取文檔列表 ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc doc : scoreDocs){ int docId = doc.doc; Document document = indexSearcher.doc(docId); System.out.println(document.get("name")); System.out.println(document.get("path")); System.out.println(document.get("size")); System.out.println(document.get("content")); } indexReader.close(); }
步驟:
建立索引庫
一、建立一個Director對象,指定索引庫保存的位置
二、基於Director對象,建立一個IndexWriter對象
三、讀取磁盤文件,對應每一個文件建立一個文檔對象
四、向文檔對象中添加域
五、把文檔對象寫入索引庫
六、關閉indexwriter對象
public void createIndex() throws Exception{ File file = new File("./index"); if (!file.exists()){ file.mkdirs(); } /* Directory directory = new RAMDirectory();//把索引庫保存到內存中,不推薦 */ //建立一個Director對象,指定索引庫保存的位置 Directory directory = FSDirectory.open(file.toPath()); //基於Direcotry對象建立一個indexWriter對象 IndexWriter indexWriter = new IndexWriter(directory,new IndexWriterConfig()); //讀取磁盤上的文件,對應每一個文件建立一個文檔對象 File orgfile = new File(); File[] files = orgfile.listFiles(); for (File f : files){ //取文件名 String filename = f.getName(); //文件的路徑 String filepath = f.getPath(); //文件的內容 String fileContent = FileUtils.readFileToString(f, "utf-8"); //文件的大小 long filesize = FileUtils.sizeOfDirectory(f); //建立field //參數1:域的名稱,參數2:域的內容,參數3:是否存儲 Field fieldName = new TextField("name",filename,Field.Store.YES); Field fieldPath = new TextField("path",filepath,Field.Store.YES); Field fieldContent = new TextField("content",fileContent,Field.Store.YES); Field fieldsize = new TextField("size",filesize+"",Field.Store.YES); //建立文檔對象 Document document = new Document(); //向文檔對象中添加域 document.add(fieldName); document.add(fieldPath); document.add(fieldContent); document.add(fieldsize); //把文檔對象寫入索引庫 indexWriter.addDocument(document); } //關閉indexwriter對象 indexWriter.close(); }
查看索引庫:使用luke工具
查詢索引庫
一、建立一個Director對象,指定索引庫的位置
二、建立一個IndexReader對象
三、建立一個IndextSearcher對象,構造方法中的參數IndexReader對象
四、建立一個Query對象,termQuery
五、執行查詢,獲得一個TopDocs對象
六、取查詢結果的總記錄數
七、取文檔列表
八、打印文檔中的內容
九、關閉IndexReader對象
public void searchIndex()throws Exception{ //建立一個Director對象,指定索引庫的位置 Directory directory=FSDirectory.open(new File("./index").toPath()); //建立一個indexReader對象 IndexReader indexReader = DirectoryReader.open(directory); //建立一個IndexSearch對象,構造方法中的參數indexReader對象 IndexSearcher indexSearcher = new IndexSearcher(indexReader); //建立一個Query對象,TermQuery Query query = new TermQuery(new Term("content","spring")); //執行查詢,獲得一個TopDocs對象 //參數1:查詢對象,參數2:查詢結果返回的最大記錄數 TopDocs topDocs = indexSearcher.search(query, 10); //取查詢結果的總記錄數 System.out.println(topDocs.totalHits); //取文檔列表 ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc doc : scoreDocs){ int docId = doc.doc; Document document = indexSearcher.doc(docId); System.out.println(document.get("name")); System.out.println(document.get("path")); System.out.println(document.get("size")); System.out.println(document.get("content")); } indexReader.close(); } }
分析器:
默認使用的是標準分析器StandardAnalyzer
查看分析器的分析效果:
一、建立一個Analyzer對象,StandardAnayzer對象
二、使用分析器對象的tokenStream方法得到宇哥tokenStream對象
三、向tokenStream對象設置一個引用,至關因而一個指針
四、調用tokenStream對象的rest方法,若是不調用拋異常
五、使用while循環遍歷tokenStream對象
六、關閉tokenStream對象
public void testTokenStream() throws Exception{ Analyzer analyzer = new StandardAnalyzer(); TokenStream tokenStream = analyzer.tokenStream("","wo shi yi ge zifuchuang"); CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class); tokenStream.reset(); while (tokenStream.incrementToken()){ System.out.println(charTermAttribute.toString()); } tokenStream.close(); }
中文分析器:IKAnalyzer
一、添加IKAnalyzer的jar包
二、把配置文件和擴展詞典添加到工程的classpath下
注意:擴展詞典嚴禁使用windows記事本編輯保證擴展詞典的編碼格式是utf-8
擴展詞典做用:添加一些新詞
停用詞詞典:無心義的詞或者是敏感詞彙
索引庫維護
常見的field:
Field類 |
數據類型 |
Analyzed 是否分詞 |
Indexed 是否索引 |
Stored 是否存儲 |
說明 |
StringField(FieldName, FieldValue,Store.YES)) |
字符串 |
N |
Y |
Y或N |
這個Field用來構建一個字符串Field,可是不會進行分詞,會將整個串存儲在索引中,好比(訂單號,身份證號等) 是否存儲在文檔中用Store.YES或Store.NO決定 |
LongField(FieldName, FieldValue,Store.YES) |
Long型 |
Y |
Y |
Y或N |
這個Field用來構建一個Long數字型Field,進行分詞和索引,好比(價格) 是否存儲在文檔中用Store.YES或Store.NO決定 |
StoredField(FieldName, FieldValue) |
重載方法,支持多種類型 |
N |
N |
Y |
這個Field用來構建不一樣類型Field 不分析,不索引,但要Field存儲在文檔中 |
TextField(FieldName, FieldValue, Store.NO) 或 TextField(FieldName, reader)
|
字符串 或 流 |
Y |
Y |
Y或N |
若是是一個Reader, lucene猜想內容比較多,會採用Unstored的策略. |
添加文檔:
public class IndexManager { public void addDoucment() throws Exception{ //建立一個IndexWriter對象,須要IKAnalyzer做爲分析器 IndexWriter indexWriter = new IndexWriter(FSDirectory.open(new File("./index").toPath()), new IndexWriterConfig(new IKAnalyzer())); //建立一個document對象 Document document = new Document(); document.add(new TextField("name","新添加的問",Field.Store.YES)); //把文檔寫入索引庫 indexWriter.addDocument(document); indexWriter.close(); } }
刪除索引庫:
public void deleteAllDocument() throws Exception{ //建立一個IndexWriter對象,須要IKAnalyzer做爲分析器 IndexWriter indexWriter = new IndexWriter(FSDirectory.open(new File("./index").toPath()), new IndexWriterConfig(new IKAnalyzer())); indexWriter.deleteAll(); indexWriter.close(); }
public void deleteDocumentByTerm()throws Exception{ IndexWriter indexWriter = new IndexWriter(FSDirectory.open(new File("./index").toPath()), new IndexWriterConfig(new IKAnalyzer())); indexWriter.deleteDocuments(new Term("name","內容")); indexWriter.close(); }
更新索引庫:
public void updateDocument()throws Exception{ IndexWriter indexWriter = new IndexWriter(FSDirectory.open(new File("./index").toPath()), new IndexWriterConfig(new IKAnalyzer())); Document document = new Document(); document.add(new TextField("name","更新的內容",Field.Store.YES)); indexWriter.updateDocument(new Term("name","內容"),document); indexWriter.close(); }
索引庫的查詢:
使用Query的子類查詢
public class SearchIndex { public void testRangeQuery()throws Exception{ IndexReader indexReader = DirectoryReader.open(FSDirectory.open(new File("./index").toPath())); IndexSearcher indexSearcher = new IndexSearcher(indexReader); //建立一個query對象 Query query = LongPoint.newRangeQuery("size", 0l, 10000l); TopDocs topDocs = indexSearcher.search(query, 10); System.out.println(topDocs.totalHits); ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc scoreDoc : scoreDocs){ int docId = scoreDoc.doc; Document document = indexSearcher.doc(docId); System.out.println(document.get("name")); } indexReader.close(); } }
使用QueryPaser進行查詢:能夠對要查詢的內容先分詞,而後基於分詞的結果再查詢
須要添加jar包lucene-queryoarser
public void testQueryParser()throws Exception{ //建立一個QueryParser對象 //參數1:默認搜索域,參數2:分析器對象 QueryParser queryParser = new QueryParser("name",new IKAnalyzer()); //使用QueryPaser對象建立一個QUery Query query = queryParser.parse("這是一個查詢的語句") //執行查詢 printResult(query); }