您好,登錄后才能下訂單哦!
數(shù)據(jù)量大,要求高的時(shí)候,數(shù)據(jù)庫內(nèi)容很多,數(shù)據(jù)庫搜索的時(shí)候?qū)?shù)據(jù)庫服務(wù)器壓力大的時(shí)候,請(qǐng)用全文檢索-Lucene框架
搜索的數(shù)據(jù)是什么?
文本(important)
多媒體
搜索的方式是什么?
不處理語義
搜索含有指定詞匯的文章
應(yīng)用范圍?
網(wǎng)頁搜索,貼吧搜索,文檔搜索等
全文檢索的要求?
搜索速度要快
結(jié)果要準(zhǔn)確
搜出多個(gè)結(jié)果的時(shí)候,把最匹配的結(jié)果放在前面,相關(guān)度排序
不區(qū)分大小寫
lucene.apache.org
apache提供了tomcat/struts/beanutils/dbUtils/..
在大量數(shù)據(jù)之中,Lucene如何實(shí)現(xiàn)快速檢索功能呢?
百度搜索---用戶請(qǐng)求發(fā)給百度服務(wù)器---返回結(jié)果
│
很多爬蟲從互聯(lián)網(wǎng)中抓了數(shù)據(jù)組織特定(快速搜索)格式放到百度服務(wù)器中的索引庫
│
Lucene管理索引庫,對(duì)外提供搜索功能
索引庫存放一堆二進(jìn)制數(shù)據(jù),可以吧索引庫理解為數(shù)據(jù)庫
如何建立索引庫的目錄?
網(wǎng)頁,文件,在java中表現(xiàn)的都是一個(gè)對(duì)象,普通javabean,用Map<String, Object>表示一個(gè)javabean里面的所有信息,比如Map<name,value>
核心包lucene-core-3.0.1.jar
特定功能包
分詞器 lucene-analyzers-3.0.1.jar
高亮關(guān)鍵字 lucene-highlighter-3.0.1.jar
高亮功能依賴的包 lucene-memory-3.0.1.jar
快速操作模式 shift + Alt +A
索引庫有兩個(gè)區(qū)
1.目錄區(qū)-分詞器劃分關(guān)鍵字,存儲(chǔ)(關(guān)鍵字與n個(gè)文章)對(duì)應(yīng)關(guān)系
2.數(shù)據(jù)區(qū)-存儲(chǔ)document
doc.add(new Field("id", idStr, Store.YES, Index.ANALYZED));
doc.add(new Field("title", article.getTitle(), Store.YES, Index.ANALYZED));
doc.add(new Field("content", article.getContent(), Store.NO, Index.ANALYZED));
Store參數(shù)
用于指定某Field的原始值是否存到數(shù)據(jù)庫中
YES - 存儲(chǔ),取出的Document中就有這個(gè)字段的值
NO - 不存儲(chǔ),取出的Document中就沒有這個(gè)字段的值
Index參數(shù)
用于指定是否把某個(gè)Field中的文本值更新到目錄區(qū)中
NO - 不更新到目錄區(qū)中,不能按此字段搜索
ANALYZED - 先把字段文本值分詞處理,把分詞后的結(jié)果更新到目錄中
NOT_ANALYZED - 不分詞,直接把Field的文本值當(dāng)作一個(gè)詞更新到目錄中,應(yīng)用場(chǎng)景:作者、日期、數(shù)字、url、文件地址
Store | Index | 應(yīng)用場(chǎng)景 |
YES | ANALYZED | 能搜索 能顯示 |
YES | NO | 不按一個(gè)字段搜索,但是顯示的時(shí)候,會(huì)顯示出這個(gè)字段。比如作者,不按作者搜索,但是顯示文章的時(shí)候會(huì)顯示作者。將一些數(shù)據(jù)存儲(chǔ)在索引庫里,可以直接拿出來用,不用再向數(shù)據(jù)庫要數(shù)據(jù)了,一次查詢顯示所有數(shù)據(jù),效率高,比如百度快照。如果這個(gè)數(shù)據(jù)特別大,那就考慮不把內(nèi)容存到索引庫里面了。 |
NO | ANALYZED | 能按這個(gè)字段搜索,能找到這個(gè)字段對(duì)應(yīng)的數(shù)據(jù)編號(hào),但是不顯示這個(gè)字段內(nèi)容。比如電子書,能按照內(nèi)容搜索,但是在結(jié)果頁面不顯示電子數(shù)內(nèi)容,只顯示電子書標(biāo)題、作者 |
NO | NOT_ANALYZED | 不允許 |
1.把Article轉(zhuǎn)為Document
Document doc = new Document();
doc.add(new Field("id", idStr, Store.YES, Index.ANALYZED));
2.添加到索引庫中
IndexWriter indexWriter =
new IndexWriter(directory, analyzer, MaxFieldLength.UNLIMITED);
indexWriter.addDocument(doc);
做兩件事情(1)把Document存到數(shù)據(jù)區(qū)中,這個(gè)時(shí)候會(huì)自動(dòng)分配一個(gè)內(nèi)部編號(hào)
(2)把一個(gè)field值(分詞或者不分詞)更新到目錄中。
搜索過程
1,把查詢字符串轉(zhuǎn)為Query對(duì)象(默認(rèn)只從title中查詢)
QueryParser queryParser = new QueryParser(Version.LUCENE_30, "title", analyzer);
Query query = queryParser.parse(queryString);
2,執(zhí)行查詢,得到中間結(jié)果 搜索目錄
IndexSearcher indexSearcher = new IndexSearcher(directory); // 指定所用的索引庫
TopDocs topDocs = indexSearcher.search(query, 100); // 最多返回前n條結(jié)果
int count = topDocs.totalHits;//關(guān)聯(lián)總條數(shù)
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
3,處理結(jié)果 根據(jù)docId取出真正的Document數(shù)據(jù)
搜索的時(shí)候 也要分詞,分成關(guān)鍵字去匹配目錄里面的關(guān)鍵字
分詞器
分詞規(guī)則
建立索引 和 搜索 都使用同一個(gè)分詞規(guī)則
MaxFieldLength
有限制10000 default
無限制 max
建立索引目錄的時(shí)候,只處理字段前多少個(gè)詞
web應(yīng)用增刪改數(shù)據(jù)庫和索引庫會(huì)引發(fā)哪些問題?
數(shù)據(jù)庫和索引庫都有文章的信息,1.浪費(fèi)存儲(chǔ)空間2.狀態(tài)同步問題
1.是否浪費(fèi)?
索引庫存放數(shù)據(jù)的原則:能被搜索的數(shù)據(jù),比如數(shù)據(jù)庫里有作者表,文章表,索引庫只存了文章表,根據(jù)作者搜索,可以搜索出作者寫的文章,而搜索不出作者的具體信息。重復(fù)的數(shù)據(jù)只是需要被搜索出來的數(shù)據(jù)。
一次搜索顯示所有數(shù)據(jù),減輕數(shù)據(jù)庫壓力。
實(shí)現(xiàn)全文搜索必須要索引庫,為了不存儲(chǔ)重復(fù)信息,是否能取消數(shù)據(jù)庫,把數(shù)據(jù)全部存到索引庫中?
不行!數(shù)據(jù)庫的一些功能,索引庫無法實(shí)現(xiàn),比如事務(wù)管理。
2.保證索引庫的狀態(tài)與數(shù)據(jù)源的狀態(tài)一致的方案:
(1)方案一:當(dāng)對(duì)數(shù)據(jù)庫做增刪改的操作時(shí),就同時(shí)對(duì)索引庫也做增刪改的操作會(huì)出現(xiàn)什么問題?在一個(gè)別人已經(jīng)存在的一個(gè)程序上,不讓你修改他們的程序,但是我要增加一個(gè)搜索功能,怎么辦?比如百度去對(duì)別人網(wǎng)頁的數(shù)據(jù)做組織成一個(gè)搜索。
(2)方案二:自己不能控制數(shù)據(jù)源的時(shí)候,定時(shí)從數(shù)據(jù)源中抓取數(shù)據(jù) -- 爬蟲的概念。定時(shí)重建索引庫,(或者定時(shí)與數(shù)據(jù)源做同步的操作),有時(shí)候做同步操作還沒有重建索引庫快呢,除非索引庫忒別大。忒別大的時(shí)候就是利用爬蟲分析網(wǎng)絡(luò)上的網(wǎng)頁是否有最新數(shù)據(jù),比如MD5摘要一下網(wǎng)頁中的內(nèi)容,(MD5摘要的內(nèi)容是不可逆的),兩個(gè)不同字符串做MD5摘要是不同,對(duì)比MD5摘要,不一樣就更新索引庫,幾百萬的數(shù)據(jù)重建是比較快的。
垂直搜索:對(duì)專業(yè)的事情有更細(xì)致的分析,比如淘寶搜索商品,能根據(jù)價(jià)格搜索特點(diǎn)商品。
根據(jù)數(shù)據(jù)源的不同,采用不同方案
1.數(shù)據(jù)源是數(shù)據(jù)庫 使用方案一或者方案二
2.數(shù)據(jù)源是網(wǎng)頁 使用方案二,流行垂直搜索
3.數(shù)據(jù)源是文件 采用JNI技術(shù):在java里面調(diào)用C或者C++程序,及時(shí)獲取操作系統(tǒng)的信息。使用方案二。
eg:利用struts2做 貼吧的增刪改查
ArticleAction{
add() {
form-->article; dao.save(article);..//保存到數(shù)據(jù)庫
indexDao.save(article)//保存到索引庫
}
delete() {
id = getparam(“id”); dao.delete(id);..//從數(shù)據(jù)庫里刪除
//從索引庫中刪除
}
modify() {
article= getById(id); form-->articel; dao.update(article);//更新到數(shù)據(jù)庫
//更新到索引庫
}
}
對(duì)索引庫的增刪改查
IndexDao{
save(article);
delete(id);
update(article);
search(str)
...
}
article 的id也要存到索引庫里,必須不分詞的存入,這是唯一標(biāo)識(shí)符,可以準(zhǔn)確鎖定article,比如可以根據(jù)id查找刪除索引庫里article。
int 類型轉(zhuǎn)化為string類型使用lucene里面的方法,存放的int類型的2進(jìn)制類型。直接用toString會(huì)將一個(gè)4字節(jié)的數(shù)據(jù)變成一個(gè)十幾個(gè)字節(jié)的數(shù)據(jù),浪費(fèi)空間,不好排序。
Ctrl + T 查看繼承關(guān)系
測(cè)試
初始化IndexWriter 如果沒有關(guān)閉,正在被使用,可能內(nèi)存上的緩存就沒有刷新到硬盤上面,沒有釋放資源,web應(yīng)用程序需要反正application監(jiān)聽器里面,在應(yīng)用程序啟動(dòng)時(shí)創(chuàng)建indexwriter對(duì)象,應(yīng)用程序退出之前關(guān)閉indexwriter對(duì)象。java程序,虛擬機(jī)退出之前關(guān)閉eindexWriter對(duì)象。指定一段代碼,在jvm退出之前執(zhí)行。
indexDir文件夾里面很多文件,有的已經(jīng)被標(biāo)記為刪除文件,為什么不直接刪除,而是標(biāo)記呢,這是應(yīng)為這個(gè)文件夾很大,頻繁修改增刪這個(gè)文件夾可能帶來效率低問題,什么時(shí)候才刪除這些標(biāo)記文件呢,lucene不忙的時(shí)候,才進(jìn)行合并或者刪除。這些被標(biāo)記刪除的文件怎么可以不被查出來呢?先查出所有數(shù)據(jù),再過濾掉del文件。優(yōu)化之后,就沒有了del文件了==合并文件,幾個(gè)小文件合并成一個(gè)大文件,減少io操作。
優(yōu)化 就是 合并文件,合并幾個(gè)小文件成一個(gè)大文件
什么時(shí)候合并文件呢
批量操作,每天重新創(chuàng)建索引庫,抓了更多文件之后合并成一個(gè)大文件放入索引庫里面,當(dāng)擴(kuò)展名相同的文件達(dá)到一定數(shù)量之后,默認(rèn)10條,最小2條,再合并==自動(dòng)優(yōu)化,
@Test
public void test() throws Exception {
LuceneUtils.getIndexWriter().optimize();
}
// 自動(dòng)合并文件
@Test
public void testAuto() throws Exception {
// 配置當(dāng)小文件的數(shù)量達(dá)到多少個(gè)后就自動(dòng)合并為一個(gè)大文件,默認(rèn)為10,最小為2.
LuceneUtils.getIndexWriter().setMergeFactor(5);
// 建立索引
Article article = new Article();
article.setId(1);
article.setTitle("準(zhǔn)備Lucene的開發(fā)環(huán)境");
article.setContent("如果信息檢索系統(tǒng)在用戶發(fā)出了檢索請(qǐng)求后再去互聯(lián)網(wǎng)上找答案,根本無法在有限的時(shí)間內(nèi)返回結(jié)果。");
new ArticleIndexDao().save(article);
}
爬蟲:功能,抓網(wǎng)頁。
把一個(gè)網(wǎng)站上面所有頁面下載下來?
方案:
0.初始條件:首頁
1.下載網(wǎng)頁得到網(wǎng)頁的內(nèi)容
2.獲取其中所有超鏈接
3.去掉已經(jīng)下載過的鏈接和棧外的鏈接
4.循環(huán)處理每一個(gè)有效的超鏈接 回到 1 沒新的鏈接出現(xiàn)就停止循環(huán)
技術(shù):
如何下載一個(gè)網(wǎng)站的URL - UrlConnection(Socket)
Http協(xié)議 發(fā)送請(qǐng)求 響應(yīng)實(shí)體內(nèi)容
1.下載網(wǎng)頁
public static String downLoad(String urlString){
URL url = new URL(urlString);
URLConnection conn = url.openConnection();
InputStream in = conn.getInputStream();
//in 流中的數(shù)據(jù)就是網(wǎng)頁內(nèi)容
2.獲取所有的超鏈接
Dom + XPath
3.去掉已經(jīng)下載過的鏈接和棧外的鏈接
把下載過的鏈接全部放到數(shù)據(jù)庫里面,或者一個(gè)集合里面,新的鏈接和集合中的鏈接進(jìn)行比較,看是否包含。
如果要做到更好一點(diǎn):出現(xiàn)網(wǎng)絡(luò)問題,好多個(gè)線程去訪問,總有幾個(gè)線程訪問不了,可以進(jìn)行3次請(qǐng)求鏈接。
多個(gè)線程不斷的從任務(wù)隊(duì)列里面拿任務(wù)
任務(wù)隊(duì)列的(需要完成的任務(wù))放到數(shù)據(jù)庫里面,停電也沒有關(guān)系。多線程從數(shù)據(jù)庫里查詢和刪除任務(wù)。隊(duì)列形式解決了遞歸的內(nèi)存溢出,停電無斷點(diǎn),不能使用多線程的問題。
在java里面用LinkedList表示隊(duì)列
addFirst() removeLast()
addLast() removeFirst()
使用多種模式:使用架構(gòu),mvc,繼承
類變多了,關(guān)系變復(fù)雜了
1.適用更復(fù)雜,要求嚴(yán)格的情況
2.代碼可讀性好
3.結(jié)構(gòu)合理,方便修改
4.方便擴(kuò)展,可維護(hù)性強(qiáng)
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。