solr学习之一 搜索基本知识
學(xué)習(xí)了一段時(shí)間的solr了,用自己的方式總結(jié)下目前學(xué)到的內(nèi)容,這是個(gè)系列文章,這里面的有些說法可能不準(zhǔn)確,也可能有問題
歡迎大家指正。
一、搜索引擎目的
搜索引擎在我們的生活中,已經(jīng)無處不在,除了我們常用的baidu、Google等,還有一些電商的搜索 比如亞馬遜搜書等。除了網(wǎng)頁搜索外,企業(yè)內(nèi)部可能涉及到知識(shí)庫搜索,一般稱為企業(yè)搜索。現(xiàn)在搜索要主要的目的是,在海量信息中,從非結(jié)構(gòu)化數(shù)據(jù)中快速找到符合我們含義的信息。注意這里的幾個(gè)關(guān)鍵詞語。
"海量信息" ?:搜索引擎一般處理的數(shù)據(jù)量很大,普通數(shù)據(jù)庫在搜索的數(shù)據(jù)量非常大的時(shí)候,比如上億條數(shù)據(jù)的時(shí)候,就算建立索引,查詢速度也不是很快,不能滿足現(xiàn)實(shí)的需求。
“符合我們的含義”:我覺得這可以稱為語意搜索(還沒有看到過這個(gè)叫法:),第一條也許數(shù)據(jù)庫還可以勉強(qiáng)達(dá)到,但是數(shù)據(jù)庫搜索難以達(dá)到符合含義這個(gè)目的,這在搜索過程中要涉及到同義詞的轉(zhuǎn)換。比如你在亞馬遜中搜索solr,可以找到Lucene、搜索引擎相關(guān)的書籍,這里面就涉及到同義詞的轉(zhuǎn)換;我覺得這是搜索引擎最重要的特征。
一般的搜索引擎都會(huì)根據(jù)相關(guān)性對(duì)我們搜索的內(nèi)容和現(xiàn)存的文檔進(jìn)行匹配,對(duì)相似度進(jìn)行打分,并且按照相似度的進(jìn)行排序,相似的排在前面。
"非結(jié)構(gòu)化數(shù)據(jù)": 這個(gè)是指沒有固定格式和固定長(zhǎng)度的數(shù)據(jù),比如一篇文章,這種數(shù)據(jù)也稱為全文數(shù)據(jù)。
?
二、搜索引擎原理
2.1 常用的非結(jié)構(gòu)化數(shù)據(jù)檢索方法
按照上節(jié)所說,搜索引擎主要處理的是非結(jié)構(gòu)化數(shù)據(jù),故名思議,非結(jié)構(gòu)化數(shù)據(jù)的特點(diǎn)就是沒有固定的結(jié)構(gòu),這也正是處理比較困難的原因;結(jié)構(gòu)化數(shù)據(jù)可以通過數(shù)據(jù)庫等方式處理。非結(jié)構(gòu)化數(shù)據(jù)如何處理,據(jù)說有兩種方法:
一種是順序搜索,比如在linux下用grep方式來搜索包含特定字符串的文檔,這在文檔數(shù)量少的時(shí)候比較有效。
二種是全文檢索,它是通過對(duì)非結(jié)構(gòu)化數(shù)據(jù)進(jìn)行結(jié)構(gòu)化轉(zhuǎn)化,對(duì)非結(jié)構(gòu)化數(shù)據(jù)進(jìn)行抽取(從文檔中抽取詞),然后重新組合,再利用它進(jìn)行搜索。
這個(gè)被抽取出來重新組織的信息稱為索引。
?第二種方法是搜索引擎中用的主要方法了。
2.2 全文檢索的三大問題
這就涉及到三個(gè)問題:1、索引里面保存什么信息?2、索引如何建立? 3、如何利用索引進(jìn)行搜索?
索引保存的是什么
讓我們思考下,既然全文搜索是通過建立索引的方式進(jìn)行搜索的,那么我們的索引內(nèi)容必然是為了方便查找到我們要的信息的。
以搜索文章為例,假如我們需要海量的文章,為了方便管理我們給這些文章進(jìn)行編號(hào),
搜索就是要找到搜索關(guān)鍵詞和文章編號(hào)的對(duì)應(yīng)關(guān)系,然后通過編號(hào)再找到對(duì)應(yīng)的文檔。那么很自然的存儲(chǔ)的索引的內(nèi)容必然有和關(guān)鍵字匹配的部分,還有文章編號(hào)的部分。
實(shí)際情況也是如此,全文搜索建立的索引簡(jiǎn)單來說就是詞和文章編號(hào)的對(duì)應(yīng)關(guān)系,由于一個(gè)詞可以放在多個(gè)文章中,所以這種索引一般就是一個(gè)個(gè)詞后面對(duì)應(yīng)一串文章編號(hào)(文檔編號(hào)鏈表)。
從文章對(duì)應(yīng)詞比較自然,所以從詞對(duì)應(yīng)文檔是文檔對(duì)應(yīng)詞的反過程,保存這種信息的索引稱為反向索引(倒排索引)。
盜用一張網(wǎng)上說明Lucene的倒排索引原理圖,solr是基于Lucene的,所以solr的索引也是倒排索引。
?
?
這里面,關(guān)鍵詞一般叫詞典,后面對(duì)應(yīng)的一串文檔號(hào)文章號(hào)叫做倒排表。
索引如何建立
創(chuàng)建索引的過程盜用個(gè)網(wǎng)上圖,索引過程如下:
我們來思考下,我們要建立的索引為倒排索引即是詞典和倒排表。
我們首先要從文檔中得到詞,所以我們首要工作是分詞,這里面用到的就是分詞組件(Tokenizer)本次得到的結(jié)果是詞元(Token)。
其次從詞元(Token)經(jīng)過語言處理組件(Linguistic Processor)的處理,輸出為詞(Term)。這一部分主要完成的是詞義轉(zhuǎn)化等
詞邊變的更純碎些。最后一步就是將詞傳遞給相關(guān)的索引組件,建立索引。
1、分詞做的主要工作
1)切詞,英語比較好拆分就是按照空格分隔,漢字要涉及到利用詞典進(jìn)行切詞或單獨(dú)按照字來進(jìn)行切詞。
2)去掉標(biāo)點(diǎn)符號(hào)。
3)去掉停詞,停詞是指語言中沒有特殊含義的副詞,比如英語中的this、is、a、漢語中的“的”等。
? ?在solr中有專門的配置文件配置停詞,stopwords_開頭的配置文件。
使得到的詞更有意義,減少索引的長(zhǎng)度,因?yàn)橥T~在很多文檔中都有,如果加到索引里面,后面的文檔號(hào)要排很長(zhǎng),專業(yè)名詞叫拉鏈過長(zhǎng)。
不光占用過多的空間,而且還會(huì)導(dǎo)致搜索變慢。
中文由于沒有明顯的詞語直接的間隔,所以中文分詞要復(fù)雜的多。solr中默認(rèn)StandardTokenizerFactory是按照字來分隔,好處是實(shí)現(xiàn)字級(jí)匹配,壞處索引變大。
也可以利用網(wǎng)上開源的分詞組件,比如:庖丁分詞、IK分詞等。
效率solr默認(rèn)的分詞的建索引效率大概是IK分詞的1倍,但是查詢效率卻慢4倍原因,是按字分詞拉鏈過長(zhǎng)原因。
2、語言處理主要工作
1)對(duì)英語來說是大小寫轉(zhuǎn)換。
2)將詞縮減或簡(jiǎn)化為詞根。(比如cars轉(zhuǎn)成car、running轉(zhuǎn)成run)
語言處理組件得到的結(jié)果是為Term(詞)。
3、將此傳遞給索引組件
1)利用詞創(chuàng)建詞典和文檔ID的對(duì)應(yīng)關(guān)系表。
2)按照字典順序?qū)υ~典進(jìn)行排序。
3)合并相同的詞典,文檔ID變成文檔ID鏈表。
實(shí)際建立的倒排索引,還包含詞在文檔中的位置、出現(xiàn)的頻次等信息。
?
搜索過程
1)我們利用搜索引擎的語法輸入查詢的語句。我們常用的搜索引擎百度
常用語法舉例子如下:
1. ?如果你想讓百度作為整體搜索而不進(jìn)行分詞,用雙引號(hào)包括。
2. ?如果你不想要一些信息可以用-號(hào),比如手機(jī)-推廣,將不會(huì)顯示百度的推廣廣告。
3. ?比如搜索關(guān)鍵詞之間是或者關(guān)系,可以通過搜索xxx|yyy方式搜索。
2) 對(duì)查詢的語句進(jìn)行詞法分析、語法分析和語義處理。
類似建索引的過程,需要進(jìn)行分詞、轉(zhuǎn)化后,還有多一個(gè)內(nèi)容要區(qū)分關(guān)鍵字和搜索詞、
關(guān)鍵字代表搜索詞之間的邏輯關(guān)系,在solr搜索中是op標(biāo)示,比如AND標(biāo)示邏輯與、
OR標(biāo)示或關(guān)系,經(jīng)過這種語法分析后形成一個(gè)語法樹。
?
3)搜索
在solr中大概分為三步完成:
1、在反向索引表中查找符合要求的文檔ID。第一次查詢返回的是文檔ID和匹配度得分。
2、根據(jù)語法樹進(jìn)行邏輯與或或等操作,得到最終符合要求的文檔ID列表。
3、通過這些文檔ID列表,結(jié)合要求查詢的內(nèi)容去查詢具體到具體的內(nèi)容信息返回。
?
?
?
4)排序返回
文檔列表查到之后,把查詢的語句當(dāng)做一個(gè)文檔,來計(jì)算被查詢的文檔和查詢到的文檔之間的相關(guān)度,并進(jìn)行打分,
相關(guān)度高的排在前面。
相關(guān)度得分的計(jì)算比較復(fù)雜,主要涉及有:
詞頻TF: 即詞在文檔中出現(xiàn)的次數(shù)。
DF: 即這個(gè)詞在多少個(gè)文檔中出現(xiàn)。
詞的權(quán)重:詞在文檔中的重要性。
?
總結(jié)
以上是生活随笔為你收集整理的solr学习之一 搜索基本知识的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hashCode()方法的性能优化
- 下一篇: 制造自己的榫卯