我 6 年前開(kāi)始為 developerWorks 編寫(xiě) Solr 和 Lucene(參見(jiàn) 參考資料)。這些年來(lái),Lucene 和 Solr 將自身建設(shè)成了一項(xiàng)堅(jiān)不可摧的技術(shù)(Lucene 作為 Java? API 的基礎(chǔ),Solr 作為搜索服務(wù))。舉例而言,它們支持著 Apple iTunes、Netflix、Wikipedia 等許多公司的基于搜索的應(yīng)用程序,它們還幫助為 IBM Watson 答問(wèn)系統(tǒng)提供支持。
多年來(lái),大部分人對(duì) Lucene 和 Solr 的使用主要集中在基于文本的搜索上。與此同時(shí),新的、有趣的大數(shù)據(jù)趨勢(shì)以及對(duì)分布式計(jì)算和大規(guī)模分析的全新(重新)關(guān)注正在興起。大數(shù)據(jù)常常還需要實(shí)時(shí)的、大規(guī)模的信息訪問(wèn)。鑒于這種轉(zhuǎn)變,Lucene 和 Solr 社區(qū)發(fā)現(xiàn)自己走到了十字路口:Lucene 的核心支柱開(kāi)始在大數(shù)據(jù)應(yīng)用程序的壓力下呈現(xiàn)老態(tài),比如對(duì) Twittersphere 的所有消息建立索引(參見(jiàn) 參考資料)。此外,Solr 在原生分布式索引支持上的匱乏,使得 IT 組織越來(lái)越難以富有成本效益的方式擴(kuò)展他們的搜索基礎(chǔ)架構(gòu)。
該社區(qū)開(kāi)始全面改革 Lucene 和 Solr 支柱(并在某些情況下改革公共 API)。我們的關(guān)注點(diǎn)已轉(zhuǎn)向?qū)崿F(xiàn)輕松的可伸縮性、近實(shí)時(shí)的索引和搜索,以及許多 NoSQL 功能 — 同時(shí)利用核心引擎功能。這次全面改革的結(jié)晶是 Apache Lucene 和 Solr 4.x 版本。這些版本首當(dāng)其沖的目標(biāo)是解決下一代、大規(guī)模、數(shù)據(jù)驅(qū)動(dòng)的訪問(wèn)和分析問(wèn)題。
本文將介紹 4.x 的要點(diǎn)功能并展示一些代碼示例。但是首先,您將動(dòng)手體驗(yàn)一個(gè)實(shí)用的應(yīng)用程序,它演示了將搜索引擎用于搜索以外的用途的一些概念。要充分理解本文,您應(yīng)熟悉 Solr 和 Lucene 的基礎(chǔ)知識(shí),尤其是 Solr 請(qǐng)求。如果不熟悉這些知識(shí),請(qǐng)參見(jiàn) 參考資料,獲取可幫助您了解 Solr 和 Lucene 的鏈接。
搜索引擎僅用于搜索文本,對(duì)吧?不對(duì)!在其核心,搜索引擎關(guān)乎快速的、高效的過(guò)濾,然后依據(jù)某種相似性概念(一種在 Lucene 和 Solr 中靈活地定義的一個(gè)概念)對(duì)數(shù)據(jù)進(jìn)行歸類(lèi)。搜索引擎還會(huì)有效地處理稀疏數(shù)據(jù)和模糊數(shù)據(jù),這些數(shù)據(jù)是現(xiàn)代數(shù)據(jù)應(yīng)用程序的標(biāo)志性特征。Lucene 和 Solr 能夠處理數(shù)字,分析復(fù)雜的地理空間問(wèn)題(您很快會(huì)看到),等等。這些功能模糊了搜索應(yīng)用程序與傳統(tǒng)的數(shù)據(jù)庫(kù)應(yīng)用程序(以及甚至 NoSQL 應(yīng)用程序)之間的界線。
例如,Lucene 和 Solr 現(xiàn)在:
一個(gè)搜索引擎不是所有數(shù)據(jù)問(wèn)題的良方。但文本搜索在過(guò)去是 Lucene 和 Solr 的主要用途,這一事實(shí)不應(yīng)阻止您使用它們解決現(xiàn)在或未來(lái)的數(shù)據(jù)需求。您可以考慮跳出眾所周知的思維模式(搜索),以新的方式使用搜索引擎。
為了演示搜索引擎如何執(zhí)行搜索以外的工作,本節(jié)剩余部分展示了一個(gè)將航空相關(guān)計(jì)數(shù)攝取到 Solr 中的應(yīng)用程序。該應(yīng)用程序?qū)?huì)查詢(xún)數(shù)據(jù)(其中大部分是文本數(shù)據(jù)),并使用 D3 JavaScript 庫(kù)(參見(jiàn) 參考資料)處理它們,然后再顯示它們。該數(shù)據(jù)集來(lái)自美國(guó)運(yùn)輸部運(yùn)輸統(tǒng)計(jì)局的研究與創(chuàng)新計(jì)數(shù)管理局 (RITA) 和 OpenFlights。該數(shù)據(jù)包含某個(gè)特定時(shí)間段的所有航班的一些詳細(xì)信息,比如起飛機(jī)場(chǎng)、目標(biāo)機(jī)場(chǎng)、晚點(diǎn)時(shí)間、晚點(diǎn)原因和航空公司信息。通過(guò)使用該應(yīng)用程序查詢(xún)此數(shù)據(jù),您可分析特定機(jī)場(chǎng)之間的晚點(diǎn)、特定機(jī)場(chǎng)上的流量增長(zhǎng)等信息。
首先讓該應(yīng)用程序正常運(yùn)行,然后查看它的一些接口。在此過(guò)程中請(qǐng)牢記,該應(yīng)用程序可通過(guò)各種方式查詢(xún) Solr 與該數(shù)據(jù)進(jìn)行交互。
首先,您需要滿(mǎn)足以下先決條件:
bash
(或類(lèi)似)shell 進(jìn)行終端訪問(wèn)。對(duì)于 Windows,您需要使用 Cygwin。我僅在 OS X 上使用 bash
shell 進(jìn)行了測(cè)試。wget
,如果您選擇使用示例代碼包中的下載腳本來(lái)下載該數(shù)據(jù)。您也可以手動(dòng)下載航班數(shù)據(jù)。 請(qǐng)參見(jiàn) 參考資料,獲取 Lucene、Solr、wget
和 Ant 下載站點(diǎn)的鏈接。
滿(mǎn)足這些先決條件之后,執(zhí)行以下步驟讓?xiě)?yīng)用程序正常運(yùn)行:
cd $SOLR_AIR
./bin/start-solr.sh
./bin/setup.sh
./bin/download-data.sh
bin/index.sh
bin/index.sh 1987
Solr Air 應(yīng)用程序正常運(yùn)行后,您就可以瀏覽該數(shù)據(jù),查看 UI 以了解您可以詢(xún)問(wèn)的問(wèn)題類(lèi)型。在瀏覽器中,您應(yīng)看到兩個(gè)主要的接口點(diǎn):地圖和搜索框。對(duì)于地圖,我首先從 D3 的優(yōu)秀的 Airport 示例開(kāi)始介紹(參見(jiàn) 參考資料)。我修改并擴(kuò)展了該代碼,以便直接從 Solr 加載所有機(jī)場(chǎng)信息,而不是從 D3 示例隨帶的示例 SCV 文件進(jìn)行加載。我還對(duì)每個(gè)機(jī)場(chǎng)執(zhí)行了一些初步的統(tǒng)計(jì)計(jì)算,您可以將鼠標(biāo)懸停在一個(gè)特定機(jī)場(chǎng)上來(lái)查看該信息。
我將使用搜索框展示一些可幫助您構(gòu)建復(fù)雜的搜索和分析應(yīng)用程序的重要功能。要理解該代碼,請(qǐng)參閱 solr/collection1/conf/velocity/map.vm 文件。
重要的關(guān)注區(qū)域包括:
每個(gè)區(qū)域都可以幫助您回答一些問(wèn)題,比如抵達(dá)一個(gè)特定機(jī)場(chǎng)的航班的平均晚點(diǎn)時(shí)間,或者在兩個(gè)機(jī)場(chǎng)之間飛行的一個(gè)飛機(jī)的最常見(jiàn)的晚點(diǎn)時(shí)間(根據(jù)航線進(jìn)行確定,或者根據(jù)某個(gè)起飛機(jī)場(chǎng)與所有鄰近機(jī)場(chǎng)之間的距離來(lái)確定)。該應(yīng)用程序使用 Solr 的統(tǒng)計(jì)功能,再結(jié)合 Solr 存在已久的分面功能來(lái)繪制機(jī)場(chǎng) “點(diǎn)” 的初始地圖并生成基本信息,比如航班總數(shù),平均、最短和最長(zhǎng)晚點(diǎn)時(shí)間。(單單此功能就是一種查找壞數(shù)據(jù)或至少查找極端異常值的出色方法。)為了演示這些區(qū)域(并展示如何輕松地集成 Solr 與 D3),我實(shí)現(xiàn)了一些輕量型 JavaScript 代碼,以執(zhí)行以下操作:
結(jié)果類(lèi)型包括:
RDU
或 SFO
)的查找。 SFO TO ATL
或 RDU TO ATL
。(不支持多個(gè)躍點(diǎn)。) near
運(yùn)算符查找鄰近的機(jī)場(chǎng),比如 near:SFO
或 near:SFO TO ATL
。likely:SFO
中一樣。/travel
請(qǐng)求處理程序的任意 Solr 查詢(xún),比如 &q=AirportCity:Francisco
。上面列表中前 3 種查詢(xún)類(lèi)型都屬于同一種類(lèi)型的變體。這些變體展示了 Solr 的中心點(diǎn)分面功能,舉例而言,顯示每條路線、每個(gè)航空公司、每個(gè)航班編號(hào)最常見(jiàn)的抵達(dá)晚點(diǎn)時(shí)間(比如 SFO TO ATL
)。near
選項(xiàng)利用新的 Lucene 和 Solr 空間功能執(zhí)行大大增強(qiáng)的空間計(jì)算,比如復(fù)雜多邊形交集。likely
選項(xiàng)展示了 Solr 的分組功能,以顯示距離某個(gè)起飛機(jī)場(chǎng)的一定范圍內(nèi)的抵達(dá)晚點(diǎn)超過(guò) 30 分鐘的機(jī)場(chǎng)。所有這些請(qǐng)求類(lèi)型都通過(guò)少量的 D3 JavaScript 來(lái)顯示信息,這增強(qiáng)了地圖功能。對(duì)于列表中的最后一種請(qǐng)求類(lèi)型,我只返回了關(guān)聯(lián)的 JSON。這種請(qǐng)求類(lèi)型支持您自行瀏覽該數(shù)據(jù)。如果在您自己的應(yīng)用程序中使用這種請(qǐng)求類(lèi)型,那么您自然地想要采用某種特定于應(yīng)用程序的方式使用響應(yīng)。
現(xiàn)在請(qǐng)自行嘗試一些查詢(xún)。例如,如果搜索 SFO TO ATL
,您應(yīng)看到類(lèi)似圖 3 的結(jié)果:
在 圖 3 中,地圖左側(cè)突出顯示了兩個(gè)機(jī)場(chǎng)。右側(cè)的 Route Stats 列表顯示了每個(gè)航空公司的每個(gè)航班最常見(jiàn)的抵達(dá)晚點(diǎn)時(shí)間。(我只加載了 1987 年的數(shù)據(jù)。)例如,該列表會(huì)告訴您,Delta 航班 156 有 5 次晚點(diǎn)五分鐘到達(dá)亞特蘭大,而且有 4 次提前 6 分鐘到達(dá)。
您可以在瀏覽器的控制臺(tái)(比如在 Mac 上的 Chrome 中,選擇 View -> Developer -> Javascript Console)和在 Solr 日志中查看基礎(chǔ)的 Solr 請(qǐng)求。我使用的 SFO-TO-ATL 請(qǐng)求(在這里為了格式化用途而分為 3 行)是:
/solr/collection1/travel?&wt=json&facet=true&facet.limit=5&fq=Origin:SFO AND Dest:ATL&q=*:*&facet.pivot=UniqueCarrier,FlightNum,ArrDelay&f.UniqueCarrier.facet.limit=10&f.FlightNum.facet.limit=10
facet.pivot
參數(shù)提供了此請(qǐng)求中的關(guān)鍵功能。facet.pivot
從航空公司(稱(chēng)為 UniqueCarrier
)移動(dòng)到 FlightNum
,再到 ArrDelay
,因此提供了 圖 3 的 Route Stats 中顯示的嵌套結(jié)構(gòu)。
如果嘗試一次 near
插入,如 near:JFK
中所示,您的結(jié)果將類(lèi)似于圖 4:
支持 near
查詢(xún)的 Solr 請(qǐng)求利用了 Solr 新的空間功能,本文后面將會(huì)詳細(xì)介紹這項(xiàng)功能。至于現(xiàn)在,您可能已通過(guò)查看請(qǐng)求本身(這里出于格式化用途而進(jìn)行了精減)而認(rèn)識(shí)到這項(xiàng)新功能的強(qiáng)大之處:
...&fq=source:Airports&q=AirportLocationJTS:"IsWithin(Circle(40.639751,-73.778925 d=3))"...
您可能已經(jīng)猜到,該請(qǐng)求查找以緯度 40.639751 和經(jīng)度 -73.778925 為中心,以 3 度(大約為 111 千米)為半徑的圓圈內(nèi)的所有機(jī)場(chǎng)。
現(xiàn)在您應(yīng)很好地認(rèn)識(shí)到 Lucene 和 Solr 應(yīng)用程序能夠以有趣的方式對(duì)數(shù)據(jù)(數(shù)字、文本或其他數(shù)據(jù))執(zhí)行切塊和切片。而且因?yàn)?Lucene 和 Solr 都是開(kāi)源的,所以可以使用適合商用的許可,您可以自由地添加自己的自定義。更妙的是,4.x 版的 Lucene 和 Solr 增加了您可以插入自己的想法和功能的位置數(shù)量,您無(wú)需大動(dòng)干戈修改代碼。在接下來(lái)查看 Lucene 4(編寫(xiě)本文時(shí)最新版為 4.4)的一些要點(diǎn)功能和隨后查看 Solr 4 要點(diǎn)功能時(shí),請(qǐng)記住這些功能。
Lucene 4 幾乎完全重寫(xiě)了 Lucene 的支柱功能,以實(shí)現(xiàn)更高的性能和靈活性。與此同時(shí),這個(gè)版本還代表著社區(qū)開(kāi)發(fā)軟件的方式上的一次巨變,這得益于 Lucene 新的隨機(jī)化單元測(cè)試框架,以及與性能相關(guān)的嚴(yán)格的社區(qū)標(biāo)準(zhǔn)。例如,隨機(jī)化測(cè)試框架(可作為一個(gè)套裝工件供任何人使用)使項(xiàng)目能夠輕松測(cè)試變量之間的交互,這些變量包括 JVM、語(yǔ)言環(huán)境、輸入內(nèi)容和查詢(xún)、存儲(chǔ)格式、計(jì)分公式,等等。(即使您絕不使用 Lucene,也會(huì)發(fā)現(xiàn)該測(cè)試框架在您自己的項(xiàng)目中很有用。)
對(duì) Lucene 的一些重要的增補(bǔ)和更改涉及到速度和內(nèi)存、靈活性、數(shù)據(jù)結(jié)構(gòu)和分面等類(lèi)別。(要了解 Lucene 中的變化的所有詳細(xì)信息,請(qǐng)查閱每個(gè) Lucene 發(fā)行版中包含的 CHANGES.txt 文件。)
盡管之前的 Lucene 版本被普遍認(rèn)為已足夠快(具體來(lái)講,該速度是相對(duì)于類(lèi)似的一般用途搜索庫(kù)而言),但 Lucene 4 中的增強(qiáng)使得許多操作比以前的版本快得多。
圖 5 中的圖表采集了 Lucene 索引的性能(以 GB 每小時(shí)來(lái)度量)。(感謝 Lucene 提交者 Mike McCandless 提供的夜間 Lucene 基礎(chǔ)測(cè)試圖表;請(qǐng)參見(jiàn) 參考資料。)圖 5 表明,在 [[?年]] 5 月的前半個(gè)月發(fā)生了巨大的性能改進(jìn):
Lucene 4 包含重大的 API 更改和增強(qiáng),這些都對(duì)該引擎有益,而且最終使您能夠執(zhí)行許多新的和有趣的功能。但從之前的 Lucene 版本升級(jí)可能需要做大量工作,尤其在您使用了任何更低級(jí)或 “專(zhuān)家” API 的時(shí)候。(IndexWriter
和 IndexReader
等類(lèi)仍然在以前的版本中得到了廣泛認(rèn)可,但舉例而言,您訪問(wèn)檢索詞矢量的方式已發(fā)生顯著變化。)制定相應(yīng)的計(jì)劃。
圖 5 顯示的改進(jìn)來(lái)自對(duì) Lucene 構(gòu)建其索引結(jié)構(gòu)和方式和它在構(gòu)建它們時(shí)處理并行性的方式所做的一系列更改(以及其他一些更改,包括 JVM 更改和固態(tài)驅(qū)動(dòng)器的使用)。這些更改專(zhuān)注于在 Lucene 將索引寫(xiě)入磁盤(pán)時(shí)消除同步;有關(guān)的詳細(xì)信息(不屬于本文的介紹范疇),請(qǐng)參閱 參考資料,以獲取 Mike McCandless 的博客文章的鏈接。
除了提高總體索引性能之外,Lucene 4 還可執(zhí)行近實(shí)時(shí) (NRT) 的索引操作。NRT 操作可顯著減少搜索引擎反映索引更改所花的時(shí)間。要使用 NRT 操作,必須在您應(yīng)用程序中,在 Lucene 的 IndexWriter
和 IndexReader
之間執(zhí)行一定的協(xié)調(diào)。清單 1(來(lái)自下載包的 src/main/java/IndexingExamples.java 文件的一個(gè)代碼段)演示了這種相互作用:
...doc = new HashSet<IndexableField>();index(writer, doc);//Get a searcherIndexSearcher searcher = new IndexSearcher(DirectoryReader.open(directory));printResults(searcher);//Now, index one more docdoc.add(new StringField("id", "id_" + 100, Field.Store.YES));doc.add(new TextField("body", "This is document 100.", Field.Store.YES));writer.addDocument(doc);//The results are still 100printResults(searcher);//Don't commit; just open a new searcher directly from the writersearcher = new IndexSearcher(DirectoryReader.open(writer, false));//The results now reflect the new document that was addedprintResults(searcher);...
在 清單 1 中,我首先為一組文檔建立了索引,并將提交到 Directory
,然后搜索該 Directory
— Lucene 中的傳統(tǒng)方法。在我繼續(xù)為另一個(gè)文檔建立索引時(shí),NRT 就會(huì)派上用場(chǎng):無(wú)需執(zhí)行全面提交,Lucene 從 IndexWriter
創(chuàng)建一個(gè)新 IndexSearcher
,然后執(zhí)行搜索。要運(yùn)行此示例,可將目錄更改為 $SOLR_AIR 目錄并執(zhí)行以下命令序列:
ant compile
cd build/classes
java -cp ../../lib/*:.IndexingExamples
備注:我將本文的多個(gè)代碼示例分組到 IndexingExamples.java 中,所以您可使用同一個(gè)命令序列運(yùn)行清單 2 和清單 4 中的示例。
打印到屏幕的輸出為:
...Num docs: 100Num docs: 100Num docs: 101...
Lucene 4 還包含內(nèi)存改進(jìn),利用了一些更高級(jí)的數(shù)據(jù)結(jié)構(gòu)(我將在 有限狀態(tài)自動(dòng)機(jī)和其他好功能 中進(jìn)行更詳細(xì)的介紹)。這些改進(jìn)不僅減少了 Lucene 的內(nèi)存占用,還大大加快了基于通配符和正則表達(dá)式的查詢(xún)速度。此外,代碼庫(kù)從處理 Java String
對(duì)象轉(zhuǎn)變?yōu)楣芾碜止?jié)數(shù)組的大量分配。(BytesRef
類(lèi)目前在 Lucene 中似乎隨處可見(jiàn)。)結(jié)果,String
開(kāi)銷(xiāo)減小了,Java 堆上的對(duì)象數(shù)量得到了更好的控制,這減少了導(dǎo)致所有工作停止的垃圾收集的發(fā)生幾率。
一些 靈活性增強(qiáng) 還帶來(lái)了性能和存儲(chǔ)改進(jìn),因?yàn)槟蔀槟膽?yīng)用程序使用的數(shù)據(jù)類(lèi)型選擇更好的數(shù)據(jù)結(jié)構(gòu)。例如,您接下來(lái)將會(huì)看到,可在 Lucene 中選擇一種方式來(lái)索引/存儲(chǔ)惟一鍵(它們是稠密的且沒(méi)有很好地壓縮),選擇一種更適合文本的稀疏性的完全不同的方式來(lái)索引/存儲(chǔ)文本。
Lucene 4.x 中的靈活性改進(jìn)為想要從 Lucene 中榨取最后一點(diǎn)質(zhì)量和性能的開(kāi)發(fā)人員(和研究人員)提供了大量的機(jī)會(huì)。為了增強(qiáng)靈活性,Lucene 提供了兩個(gè)新的明確定義的插件點(diǎn)。兩個(gè)插件點(diǎn)都顯著影響著開(kāi)發(fā)和使用 Lucene 的方式。
Lucene 分段是整個(gè)索引的一個(gè)子集。從許多方面來(lái)看,分段是一個(gè)自成一體的微型索引。Lucene 使用了分段平衡索引的搜索可用性和寫(xiě)入速度,以便構(gòu)建其索引。分段是索引期間只需編寫(xiě)一次的文件,在寫(xiě)入期間,每次提交時(shí)都會(huì)創(chuàng)建一個(gè)新分段。在后臺(tái),默認(rèn)情況下,Lucene 會(huì)定期將較小的分段合并到已交到的分段中,以提高讀取性能和減少系統(tǒng)開(kāi)銷(xiāo)。您可練習(xí)完全掌控這一過(guò)程。
第一個(gè)新插件點(diǎn)設(shè)計(jì)用來(lái)為您提供對(duì) Lucene 分段 的編碼和解碼的深入控制。Codec
類(lèi)定義了這項(xiàng)功能。Codec
為您提供了控制帖子列表的格式(也就是倒排索引)、Lucene 存儲(chǔ)、加權(quán)因子(也稱(chēng)為范數(shù) (norm))等的能力。
在一些應(yīng)用程序中,您可能想要實(shí)現(xiàn)自己的 Codec
。但您可能更想要更改用于索引中的一個(gè)文檔字段子集的 Codec
。為了理解這一點(diǎn),考慮您放入應(yīng)用程序中的數(shù)據(jù)類(lèi)型可能會(huì)對(duì)您有所幫助。例如,標(biāo)識(shí)字段(例如您的主鍵)通常是惟一的。因?yàn)橹麈I在一個(gè)文檔中僅出現(xiàn)一次,所以您可能希望采用與編碼文章正文文本不同的方式對(duì)它們進(jìn)行編碼。在這些情況下,您不會(huì)實(shí)際更改 Codec
。相反,您更改的是 Codec
所委托的一個(gè)更低級(jí)類(lèi)。
為了演示之目的,我將展示一個(gè)代碼示例,其中使用了我最喜愛(ài)的 Codec
SimpleTextCodec
。SimpleTextCodec
從名稱(chēng)就可以明白其含義:一個(gè)用于編碼簡(jiǎn)單文本中的索引的 Codec
。(SimpleTextCodec
編寫(xiě)并通過(guò) Lucene 龐大的測(cè)試框架的事實(shí),就是對(duì) Lucene 增強(qiáng)的靈活性的見(jiàn)證。)SimpleTextCodec
太大、太慢,不適合在生產(chǎn)環(huán)境中使用,但它是了解 Lucene 索引的幕后工作原理的不錯(cuò)方式,這正是我最喜愛(ài)它的原因。清單 2 中的代碼將一個(gè) Codec
實(shí)例更改為 SimpleTextCodec
:
Codec
實(shí)例的示例...conf.setCodec(new SimpleTextCodec());File simpleText = new File("simpletext");directory = new SimpleFSDirectory(simpleText);//Let's write to disk so that we can see what it looks likewriter = new IndexWriter(directory, conf);index(writer, doc);//index the same docs as before...
通過(guò)運(yùn)行 清單 2 的代碼,您會(huì)創(chuàng)建一個(gè)本地 build/classes/simpletext 目錄。要查看 Codec
的實(shí)際運(yùn)用,可更改到 build/classes/simpletext 并在文本編輯器中打開(kāi) .cfs 文件。您可看到,.cfs 文件確實(shí)是簡(jiǎn)單文本,就像清單 3 中的代碼段一樣:
... term id_97 doc 97 term id_98 doc 98 term id_99 doc 99ENDdoc 0 numfields 4 field 0 name id type string value id_100 field 1 name body type string value This is document 100....
在很大程度上,只有在您處理極大量索引和查詢(xún)量時(shí),或者如果您是一位喜愛(ài)使用裸機(jī)的研究人員或搜索引擎內(nèi)行,更改 Codec
才有用。在這些情況下更改 Codec
之前,請(qǐng)使用實(shí)際數(shù)據(jù)對(duì)各種可用的 Codec
執(zhí)行廣泛的測(cè)試。Solr 用戶(hù)可修改簡(jiǎn)單的配置項(xiàng)來(lái)設(shè)置和更改這些功能。請(qǐng)參閱 Solr 參考指南,了解更多的細(xì)節(jié)(參見(jiàn) 參考資料)。
第二個(gè)重要的新插件點(diǎn)讓 Lucene 的計(jì)分模型變得完全可插拔。您不再局限于使用 Lucene 的默認(rèn)計(jì)分模型,一些批評(píng)者聲稱(chēng)它太簡(jiǎn)單了。如果您喜歡的話,可以使用備用的計(jì)分模型,比如來(lái)自 Randomness 的 BM25 和 Divergence(參見(jiàn) 參考資料),或者您可以編寫(xiě)自己的模型。為什么編寫(xiě)自己的模型?或許您的 “文檔” 代表著分子或基因;您想要采用一種快速方式來(lái)對(duì)它們分進(jìn)行類(lèi),但術(shù)語(yǔ)頻率和文檔頻率并不適用?;蛘吣赡芟胍囼?yàn)?zāi)谝黄芯课恼轮凶x到的一種新計(jì)分模型,以查看它在您內(nèi)容上的工作情況。無(wú)論原因是什么,更改計(jì)分模型都需要您在建立索引時(shí)通過(guò) IndexWriterConfig.setSimilarity(Similarity)
方法更改該模型,并在搜索時(shí)通過(guò) IndexSearcher.setSimilarity(Similarity)
方法更改它。清單 4 演示了對(duì) Similarity
的更改,首先運(yùn)行一個(gè)使用默認(rèn) Similarity
的查詢(xún),然后使用 Lucene 的 BM25Similarity
重新建立索引并重新運(yùn)行該查詢(xún):
Similarity
conf = new IndexWriterConfig(Version.LUCENE_44, analyzer);directory = new RAMDirectory();writer = new IndexWriter(directory, conf);index(writer, DOC_BODIES);writer.close();searcher = new IndexSearcher(DirectoryReader.open(directory));System.out.println("Lucene default scoring:");TermQuery query = new TermQuery(new Term("body", "snow"));printResults(searcher, query, 10);BM25Similarity bm25Similarity = new BM25Similarity();conf.setSimilarity(bm25Similarity);Directory bm25Directory = new RAMDirectory();writer = new IndexWriter(bm25Directory, conf);index(writer, DOC_BODIES);writer.close();searcher = new IndexSearcher(DirectoryReader.open(bm25Directory));searcher.setSimilarity(bm25Similarity);System.out.println("Lucene BM25 scoring:");printResults(searcher, query, 10);
運(yùn)行 清單 4 中的代碼并檢查輸出。請(qǐng)注意,計(jì)分確實(shí)不同。BM25 方法的結(jié)果是否更準(zhǔn)確地反映了一個(gè)用戶(hù)想要的結(jié)果集,最終取決于您和您用戶(hù)的決定。我建議您設(shè)置自己的應(yīng)用程序,讓您能夠輕松地運(yùn)行試驗(yàn)。(A/B 測(cè)試應(yīng)有所幫助。)然后不僅對(duì)比了 Similarity
結(jié)果,還要對(duì)比了各種查詢(xún)結(jié)構(gòu)、Analyzer
和其他許多方面的結(jié)果。
對(duì) Lucene 的數(shù)據(jù)結(jié)構(gòu)和算法的全面修改在 Lucene 4 中帶來(lái)兩個(gè)特別有趣的改進(jìn):
DocValues 和 FSA 都為某些可能影響您應(yīng)用程序的操作類(lèi)型提供了重大的新性能優(yōu)勢(shì)。
在 DocValues 端,在許多情況下,應(yīng)用程序需要非??斓仨樞蛟L問(wèn)一個(gè)字段的所有值?;蛘邞?yīng)用程序需要對(duì)快速查找這些值來(lái)進(jìn)行排序或分面,而不會(huì)導(dǎo)致從索引構(gòu)建內(nèi)存型版本(這個(gè)過(guò)程也稱(chēng)為非反轉(zhuǎn) (un-inverting))的成本。DocValues 設(shè)計(jì)用來(lái)滿(mǎn)足以下需求類(lèi)型。
一個(gè)沒(méi)有大量通配符或模糊查詢(xún)的應(yīng)用程序應(yīng)該看到使用 FSA 帶來(lái)的重大性能改進(jìn)。Lucene 和 Solr 現(xiàn)在支持利用了 FSA 的查詢(xún)自動(dòng)建議和拼寫(xiě)檢查功能。而且 Lucene 默認(rèn)的 Codec
顯著減少了磁盤(pán)和內(nèi)存空間占用,在幕后使用 FSA 來(lái)存儲(chǔ)術(shù)語(yǔ)字典(Lucene 在搜索期間用于查詢(xún)術(shù)語(yǔ)的結(jié)構(gòu))。FSA 在語(yǔ)言處理方面擁有許多用途,所以您也可能發(fā)現(xiàn) Lucene 的 FSA 功能對(duì)其他應(yīng)用程序很有益。
圖 6 顯示了一個(gè)使用單詞 mop、pop、moth、star、stop 和 top 以及關(guān)聯(lián)的權(quán)重,從 http://examples.mikemccandless.com/fst.py 構(gòu)建的 FSA。在這個(gè)示例中,您可以想象從 moth
等輸入開(kāi)始,將它分解為它的字符 (m-o-t-h),然后按照 FSA 中的弧線運(yùn)行。
清單 5(摘自本文的示例代碼下載中的 FSAExamples.java 文件)顯示了使用 Lucene 的 API 構(gòu)建您自己的 FSA 的簡(jiǎn)單示例:
String[] words = {"hockey", "hawk", "puck", "text", "textual", "anachronism", "anarchy"};Collection<BytesRef> strings = new ArrayList<BytesRef>();for (String word : words) { strings.add(new BytesRef(word));}//build up a simple automaton out of several wordsAutomaton automaton = BasicAutomata.makeStringUnion(strings);CharacterRunAutomaton run = new CharacterRunAutomaton(automaton);System.out.println("Match: " + run.run("hockey"));System.out.println("Match: " + run.run("ha"));
在 清單 5 中,我從各種單詞構(gòu)建了一個(gè) Automaton
并將它提供給 RunAutomaton
。從名稱(chēng)可以看出,RunAutomaton
通過(guò)自動(dòng)化來(lái)運(yùn)行輸入,并在這種情況下與從 清單 5 末尾的打印語(yǔ)句中捕獲的輸入字符串進(jìn)行匹配。盡管這個(gè)示例很普通,但它為理解我將留給讀者探索的 Lucene API 中的更多高級(jí)功能(和 DocValues)奠定了基礎(chǔ)。(請(qǐng)參見(jiàn) 參考資料 以獲取相關(guān)鏈接。)
在其核心,分面生成一定數(shù)量的文檔屬性,為用戶(hù)提供一種縮小其搜索結(jié)果的輕松方式,無(wú)需他們猜測(cè)要向查詢(xún)中添加哪些關(guān)鍵詞。例如,如果有人在一個(gè)購(gòu)物網(wǎng)站上搜索電視,那么分面功能會(huì)告訴他們哪些制造商生產(chǎn)了多少種電視型號(hào)。分面也常常用于增強(qiáng)基于搜索的業(yè)務(wù)分析和報(bào)告工具。通過(guò)使用更高級(jí)的分面功能,您為用戶(hù)提供了以有趣方式對(duì)分面進(jìn)行切片和切塊的能力。
分面很久以來(lái)都是 Solr 的標(biāo)志性特性(自 1.1 版開(kāi)始)。現(xiàn)在 Lucene 擁有自己獨(dú)立的分面模塊可供 Lucene 應(yīng)用程序使用。Lucene 的分面模塊在功能上沒(méi)有 Solr 豐富,但它確實(shí)提供了一些有趣的權(quán)衡。Lucene 的分面模塊不是動(dòng)態(tài)的,因?yàn)槟仨氃谒饕龝r(shí)制定一些分面決策。但它是分層的,而且它沒(méi)有將字段動(dòng)態(tài)非反轉(zhuǎn) (un-invert) 到內(nèi)存中的成本。
清單 6(包含在示例代碼的 FacetExamples.java 文件中)顯示了 Lucene 的一些新的分面功能:
...DirectoryTaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(facetDir, IndexWriterConfig.OpenMode.CREATE);FacetFields facetFields = new FacetFields(taxoWriter);for (int i = 0; i < DOC_BODIES.length; i++) { String docBody = DOC_BODIES[i]; String category = CATEGORIES[i]; Document doc = new Document(); CategoryPath path = new CategoryPath(category, '/'); //Setup the fields facetFields.addFields(doc, Collections.singleton(path));//just do a single category path doc.add(new StringField("id", "id_" + i, Field.Store.YES)); doc.add(new TextField("body", docBody, Field.Store.YES)); writer.addDocument(doc);}writer.commit();taxoWriter.commit();DirectoryReader reader = DirectoryReader.open(dir);IndexSearcher searcher = new IndexSearcher(reader);DirectoryTaxonomyReader taxor = new DirectoryTaxonomyReader(taxoWriter);ArrayList<FacetRequest> facetRequests = new ArrayList<FacetRequest>();CountFacetRequest home = new CountFacetRequest(new CategoryPath("Home", '/'), 100);home.setDepth(5);facetRequests.add(home);facetRequests.add(new CountFacetRequest(new CategoryPath("Home/Sports", '/'), 10));facetRequests.add(new CountFacetRequest(new CategoryPath("Home/Weather", '/'), 10));FacetSearchParams fsp = new FacetSearchParams(facetRequests);FacetsCollector facetsCollector = FacetsCollector.create(fsp, reader, taxor);searcher.search(new MatchAllDocsQuery(), facetsCollector);for (FacetResult fres : facetsCollector.getFacetResults()) { FacetResultNode root = fres.getFacetResultNode(); printFacet(root, 0);}
清單 6 中的重要代碼(除正常的 Lucene 索引和搜索外)包含在 FacetFields
、FacetsCollector
、TaxonomyReader
和 TaxonomyWriter
類(lèi)的使用中。FacetFields
在文檔中創(chuàng)建了合適的字段條目,在建立索引時(shí)可與 TaxonomyWriter
結(jié)合使用。在搜索時(shí),可結(jié)合使用 TaxonomyReader
與 FacetsCollector
,以獲取每個(gè)類(lèi)別的正確計(jì)數(shù)。另請(qǐng)注意,Lucene 的分面模塊創(chuàng)建了一個(gè)輔助索引,要讓該索引生效,必須讓它與主要索引保持同步。使用您在前面示例的相同命令中使用的順序來(lái)運(yùn)行 清單 6 的代碼,但將 java
命令中的 FacetExamples
替換為 IndexingExamples
。您應(yīng)該得到:
Home (0.0) Home/Children (3.0) Home/Children/Nursery Rhymes (3.0) Home/Weather (2.0) Home/Sports (2.0) Home/Sports/Rock Climbing (1.0) Home/Sports/Hockey (1.0) Home/Writing (1.0) Home/Quotes (1.0) Home/Quotes/Yoda (1.0) Home/Music (1.0) Home/Music/Lyrics (1.0)...
請(qǐng)注意,在這個(gè)特定的實(shí)現(xiàn)中,我未包含 Home
分面的計(jì)數(shù),因?yàn)榘鼈兛赡苄枰芨叩某杀尽T撨x項(xiàng)可通過(guò)設(shè)置適當(dāng)?shù)?FacetIndexingParams
來(lái)提供支持,這里沒(méi)有提供有關(guān)介紹。Lucene 的分面模塊擁有我未介紹的額外功能。您可以查閱 參考資料 中的文章,探索它們本文未涉及的其他新的 Lucene 功能?,F(xiàn)在,我們來(lái)看一看 Solr 4.x。
從 API 角度講,Solr 4.x 的外觀與以前的版本很相似。但是 4.x 包含眾多增強(qiáng),使它比以往更容易使用并且更容易擴(kuò)展。Solr 還使您能夠回答新的問(wèn)題類(lèi)型,同時(shí)利用我剛列出的許多 Lucene 增強(qiáng)。其他更改主要針對(duì)開(kāi)發(fā)人員的上手體驗(yàn)。例如,全新的 Solr 參考指南(參見(jiàn) 參考資料)為每個(gè) Solr 版本(從 4.4 版開(kāi)始)提供了具有圖書(shū)質(zhì)量的文檔。而且 Solr 新的無(wú)模式功能使新數(shù)據(jù)能快速添加到索引中,無(wú)需首先定義一種模式。您稍后將看到 Solr 的無(wú)模式功能。讓我們先來(lái)看一下 Solr 中一些新的搜索、分面和相關(guān)性增強(qiáng),您已在 Solr Air 應(yīng)用程序中看到了其中一些功能的實(shí)際應(yīng)用。
一些新 Solr 4 功能設(shè)計(jì)用來(lái)在索引端和 “搜索和分面” 端更容易地構(gòu)建下一代數(shù)據(jù)驅(qū)動(dòng)應(yīng)用程序。表 1 總結(jié)了要點(diǎn)功能以及適用的命令和代碼示例:
名稱(chēng) | 描述 | 示例 |
---|---|---|
中心點(diǎn)分面 | 收集所有分面的子分面計(jì)數(shù),通過(guò)父分面過(guò)濾。請(qǐng)參閱 Solr Air 示例 了解更多詳細(xì)信息。 | 各種字段上的中心點(diǎn):http://localhost:8983/solr/collection1/travel?&wt=json&facet=true&facet.limit=5&fq=&q=*:*&facet.pivot=Origin,Dest,UniqueCarrier,FlightNum,ArrDelay&indent=true |
新的相關(guān)性功能查詢(xún) | 在一個(gè)功能查詢(xún)中訪問(wèn)各種索引級(jí)統(tǒng)計(jì)數(shù)據(jù),比如文檔頻率和檢索詞頻率。 | 在所有返回的文檔中添加檢索詞 Origin:SFO 的 Document 頻率:http://localhost:8983/solr/collection1/travel?&wt=json&q=*:*&fl=*, {!func}docfreq('Origin',%20'SFO')&indent=true 請(qǐng)注意,這個(gè)命令也使用了新的 DocTransformers 功能。 |
聯(lián)接 | 表示更復(fù)雜的文檔關(guān)系,然后在搜索時(shí)聯(lián)接它們。更復(fù)雜的聯(lián)接計(jì)劃將在未來(lái)的 Solr 版本中實(shí)現(xiàn)。 | 僅返回機(jī)場(chǎng)數(shù)據(jù)集中出現(xiàn)了其起飛機(jī)場(chǎng)代碼的航班(并將結(jié)果與一個(gè)請(qǐng)求對(duì)比,而不使用聯(lián)接):http://localhost:8983/solr/collection1/travel?&wt=json&indent=true&q={!join%20from=IATA%20to=Origin}*:* |
Codec 支持 | 更改索引的 Codec 和各個(gè)字段的發(fā)布格式。 | 對(duì)一個(gè)字段使用 SimpleTextCodec :<fieldType name="string_simpletext" class="solr.StrField" postingsFormat="SimpleText" /> |
新的更新處理器 | 在建立索引之前,但在文檔發(fā)送到 Solr 之后,使用 Solr 的 Update Processor 框架插入更改文檔的代碼。 |
|
原子更新 | 發(fā)送文檔中已更新的部分,讓 Solr 負(fù)責(zé)剩余部分。 | 從命令行,使用 cURL ,將文檔 243551 的來(lái)源更改為 FOO :curl http://localhost:8983/solr/update -H 'Content-type:application/json' -d ' [{"id":"243551","Origin":{"set":"FOO"}}]' |
您可在瀏覽器地址欄(而不是在 Solr Air UI 中)對(duì) Solr Air 演示數(shù)據(jù)運(yùn)行 表 1 中的前 3 個(gè)示例命令。
有關(guān)相關(guān)性功能、連接和 Codec
— 以及其他新 Solr 4 功能 — 的更多細(xì)節(jié),請(qǐng)參見(jiàn) 參考資料 獲取 Solr Wiki 和其他位置的相關(guān)鏈接。
或許最近幾年 Solr 中最重大的變化是,構(gòu)建一個(gè)多節(jié)點(diǎn)可擴(kuò)展搜索解決方案變得簡(jiǎn)單了許多。在 Solr 4.x 中,比以往更容易將 Solr 擴(kuò)展為數(shù)十億條記錄的權(quán)威的存儲(chǔ)和訪問(wèn)機(jī)制 — 同時(shí)獲得 Solr 已為大家熟知的搜索和分面功能。此外,您可以在容量需求更改時(shí)重新平衡您的集群,并利用樂(lè)觀鎖定、內(nèi)容原子更新,以及實(shí)時(shí)數(shù)據(jù)檢索,即使它尚未建立索引。Solr 中新的分布式功能被統(tǒng)稱(chēng)為 SolrCloud。
SolrCloud 是如何工作的?Solr 4 在(可選的)分布式模式下運(yùn)行時(shí),發(fā)送給它的文檔會(huì)依據(jù)一種哈希機(jī)制來(lái)路由到集群中的某個(gè)節(jié)點(diǎn)(被稱(chēng)為前導(dǎo)點(diǎn) (leader))。前導(dǎo)點(diǎn)負(fù)責(zé)將文檔索引到一個(gè)分片 (shard)。一個(gè)分片是一個(gè)索引,由一個(gè)前導(dǎo)點(diǎn)和 0 或多個(gè)副本組成。作為演示,我們假設(shè)您有 4 個(gè)機(jī)器和 2 個(gè)分片。在 Solr 啟動(dòng)時(shí),4 個(gè)機(jī)器中的每一個(gè)與其他 3 個(gè)通信。兩個(gè)機(jī)器被選為前導(dǎo)點(diǎn),一個(gè)前導(dǎo)點(diǎn)對(duì)應(yīng)一個(gè)分片。其他兩個(gè)節(jié)點(diǎn)自動(dòng)成為一個(gè)分片的副本。如果一個(gè)前導(dǎo)點(diǎn)因?yàn)槟撤N原因而發(fā)生故障,那么分片副本(在此情況下是惟一的副本)也會(huì)成為前導(dǎo)點(diǎn),以保證系統(tǒng)仍能正常運(yùn)行。您可以從這個(gè)示例得出結(jié)論,在生成系統(tǒng)中,必須有足夠多個(gè)節(jié)點(diǎn)參與其中,才能確保您可處理系統(tǒng)宕機(jī)。
要查看 SolrCloud 的實(shí)際應(yīng)用,可使用一個(gè) -z
標(biāo)志運(yùn)行 Solr Air 示例 中使用的 start-solr.sh 腳本,啟動(dòng)一個(gè)雙節(jié)點(diǎn)、雙分片的系統(tǒng)。從 *NIX 命令行,首先關(guān)閉您的舊實(shí)例:
kill -9 PROCESS_ID
然后重新啟動(dòng)系統(tǒng):
bin/start-solr.sh -c -z
Zookeeper 是一個(gè)分布式協(xié)調(diào)系統(tǒng),設(shè)計(jì)用來(lái)選擇前導(dǎo)點(diǎn),建立一個(gè)配額數(shù)量,并執(zhí)行其他任務(wù)來(lái)協(xié)調(diào)集群中的節(jié)點(diǎn)。得益于 Zookeeper,Solr 集群絕不會(huì)遇到 “分裂腦” 癥狀,也就是說(shuō),由于一個(gè)分區(qū)事件,集群的一部分的行為與剩余部分是獨(dú)立的。請(qǐng)參見(jiàn) 參考資料,了解 Zookeeper 的更多信息。
-c
標(biāo)志將會(huì)擦除舊索引。-z
標(biāo)志告訴 Solr 啟動(dòng) Apache Zookeeper 的一個(gè)嵌入式版本。
在瀏覽器中打開(kāi) SolrCloud 管理頁(yè)面 http://localhost:8983/solr/#/~cloud,以確認(rèn)有兩個(gè)節(jié)點(diǎn)參與到集群中。您現(xiàn)在可以為您的內(nèi)容重新建立索引,它將分散在兩個(gè)節(jié)點(diǎn)上。對(duì)系統(tǒng)的所有查詢(xún)也會(huì)自動(dòng)分布。您對(duì)兩個(gè)節(jié)點(diǎn)的 “匹配所有文檔” 搜索應(yīng)獲得與對(duì)一個(gè)節(jié)點(diǎn)的搜索相同的命中數(shù)。
start-solr.sh 腳本使用以下命令對(duì)第一個(gè)節(jié)點(diǎn)啟動(dòng) Solr:
java -Dbootstrap_confdir=$SOLR_HOME/solr/collection1/conf -Dcollection.configName=myconf -DzkRun -DnumShards=2 -jar start.jar
該腳本告訴第二個(gè)節(jié)點(diǎn) Zookeeper 位于何處:
java -Djetty.port=7574 -DzkHost=localhost:9983 -jar start.jar
嵌入式 Zookeeper 非常適合入門(mén),但為了確保生產(chǎn)系統(tǒng)的高可用性和容錯(cuò)能力,請(qǐng)?jiān)谀募褐性O(shè)置一組獨(dú)立的 Zookeeper 實(shí)例。
以 SolrCloud 功能為基礎(chǔ),提供了對(duì) NRT 和許多類(lèi)似 NoSQL 的功能的支持,比如:
Solr 中的許多分布式功能和 NoSQL 功能(比如文檔和事務(wù)日志的自動(dòng)版本控制)會(huì)開(kāi)箱即用地運(yùn)行。對(duì)于其他一些功能,表 2 中的描述和示例將很有幫助:
名稱(chēng) | 描述 | 示例 |
---|---|---|
實(shí)時(shí)獲取 | 按 ID 檢索一個(gè)文檔,無(wú)論它的索引或分發(fā)狀態(tài)如何。 | 獲取 ID 為 243551 的文檔:http://localhost:8983/solr/collection1/get?id=243551 |
分片拆分 | 將您的索引拆分為更小的分片,以便它們可遷移到集群中的新節(jié)點(diǎn)。 | 將 shard1 拆分為兩個(gè)分片:http://localhost:8983/solr/admin/collections?action=SPLITSHARD&collection=collection1&shard=shard1 |
NRT | 使用 NRT 搜索新內(nèi)容的速度比以前的版本快得多。 | 在您的 solrconfig.xml 文件中打開(kāi) <autoSoftCommit> 。例如: <autoSoftCommit> |
文檔路由 | 指定哪些文檔位于哪些節(jié)點(diǎn)上。 | 確保一個(gè)用戶(hù)的所有數(shù)據(jù)位于某些機(jī)器上。請(qǐng)查閱 Joel Bernstein 的博客文章(參見(jiàn) 參考資料)。 |
集合 | 根據(jù)需要,使用 Solr 新的集合 API 以編程方式創(chuàng)建、刪除或更新集合。 | 創(chuàng)建一個(gè)名為 hockey 的新集合:http://localhost:8983/solr/admin/collections?action=CREATE&name=hockey&numShards=2 |
數(shù)據(jù)集合很少?zèng)]有模式。無(wú)模式 是一個(gè)營(yíng)銷(xiāo)詞匯,源自數(shù)據(jù)社區(qū)引擎對(duì) “告訴” 引擎模式是什么的數(shù)據(jù)做出適當(dāng)反應(yīng)的能力,而無(wú)需引擎指定數(shù)據(jù)必須采用的格式。例如,Solr 可接受 JSON 輸入,可基于 JSON 中隱式定義的模式適當(dāng)?shù)貫閮?nèi)容建立索引。正如有人在 Twitter 上對(duì)我所說(shuō)的,更少模式 是一個(gè)比無(wú)模式 更好的詞匯,因?yàn)槟谝粋€(gè)位置上(比如一個(gè) JSON 文檔)定義模式,而不是在兩個(gè)位置上(比如一個(gè) JSON 文檔和 Solr)。
基于我的經(jīng)驗(yàn),在絕大多數(shù)情況下,您都不應(yīng)在生產(chǎn)環(huán)境中使用無(wú)模式,除非您喜歡在凌晨?jī)牲c(diǎn),在您的系統(tǒng)認(rèn)為它擁有一種數(shù)據(jù)類(lèi)型而實(shí)際擁有另一種類(lèi)型的時(shí)候調(diào)試錯(cuò)誤。
Solr 的無(wú)模式功能使得客戶(hù)端能夠快速添加內(nèi)容,而不會(huì)產(chǎn)生首先定義一個(gè) schema.xml 文件的開(kāi)銷(xiāo)。Solr 檢查傳入的數(shù)據(jù),并通過(guò)一個(gè)級(jí)聯(lián)的值分析器集合傳遞該數(shù)據(jù)。值分析器猜測(cè)數(shù)據(jù)的類(lèi)型,然后自動(dòng)向內(nèi)部模式添加字段并向索引添加內(nèi)容。
典型的生產(chǎn)系統(tǒng)(也有一些例外)不應(yīng)使用無(wú)模式,因?yàn)橹挡聹y(cè)并不總是完美的。例如,Solr 第一次看到一個(gè)新字段時(shí),它可能將該字段識(shí)別為一個(gè)整數(shù),進(jìn)而在底層模式中定義一個(gè)整數(shù) FieldType
。但您可能發(fā)現(xiàn),在 3 星期后該字段無(wú)法用于搜索,因?yàn)樵?Solr 看到的剩余內(nèi)容中,該字段都由浮點(diǎn)值組成。
但是,無(wú)模式對(duì)您很少能控制其格式的內(nèi)容的早期開(kāi)發(fā)或索引特別有幫助。例如,表 2 包含一個(gè)使用 Solr 中的集合 API 來(lái)創(chuàng)建一個(gè)新集合的示例:
http://localhost:8983/solr/admin/collections?action=CREATE&name=hockey&numShards=2)
創(chuàng)建集合后,您可以使用無(wú)模式向它添加內(nèi)容。但是,首先請(qǐng)看看當(dāng)前的模式。作為實(shí)現(xiàn)無(wú)模式支持的一部分,Solr 還添加了具象狀態(tài)傳輸 (Representational State Transfer, REST) API 來(lái)訪問(wèn)該模式。您可通過(guò)在瀏覽器中打開(kāi) http://localhost:8983/solr/hockey/schema/fields(或在命令行上使用 cURL
),看到為 hockey 集合定義的所有字段。您會(huì)看到 Solr Air 示例中的所有字段。該模式使用這些字段,因?yàn)槲业哪J(rèn)配置使用 create
選項(xiàng)作為新集合的基礎(chǔ)。如果愿意的話,您可改寫(xiě)該配置。(邊注:示例代碼下載文件中包含的 setup.sh 腳本使用新的模式 API 來(lái)自動(dòng)創(chuàng)建所有字段定義。)
要使用無(wú)模式添加到集合中,可運(yùn)行:
bin/schemaless-example.sh
以下 JSON 添加到您之前創(chuàng)建的 hockey 集合中:
[ { "id": "id1", "team": "Carolina Hurricanes", "description": "The NHL franchise located in Raleigh, NC", "cupWins": 1 }]
通過(guò)檢查將此 JSON 添加到集合之前的模式可以知道,team
、description
和 cupWins
字段是新的。該腳本運(yùn)行時(shí),Solr 會(huì)自動(dòng)猜測(cè)它們的類(lèi)型,并在模式中創(chuàng)建這些字段。要驗(yàn)證此操作,可在 http://localhost:8983/solr/hockey/schema/fields 上刷新結(jié)果。您現(xiàn)在應(yīng)看到 team
、description
和 cupWins
都已在字段列表中定義。
Solr 對(duì)基于點(diǎn)的空間搜索的長(zhǎng)久支持,使您能夠找到距離某個(gè)點(diǎn)的一定距離內(nèi)的所有文檔。盡管 Solr 支持在一個(gè) n 維空間中使用此方法,但大部分人都使用它執(zhí)行地理空間搜索(例如,查找我的位置附近的所有飯店)。但是直到現(xiàn)在,Solr 仍不支持更加復(fù)雜的空間功能,比如對(duì)多邊形建立索引或在建立了索引的多邊形內(nèi)執(zhí)行搜索。新的空間包中的一些要點(diǎn)包括:
Is Within
、Contains
和 IsDisjointTo
的查詢(xún)支持Solr Air 應(yīng)用程序的模式擁有多種字段類(lèi)型,它們?cè)O(shè)置來(lái)利用這種新的空間功能。我定義了兩種字段類(lèi)型來(lái)處理機(jī)場(chǎng)數(shù)據(jù)的經(jīng)度和緯度:
<fieldType name="location_jts" class="solr.SpatialRecursivePrefixTreeFieldType" distErrPct="0.025" spatialContextFactory="com.spatial4j.core.context.jts.JtsSpatialContextFactory" maxDistErr="0.000009" units="degrees"/><fieldType name="location_rpt" class="solr.SpatialRecursivePrefixTreeFieldType" distErrPct="0.025" geo="true" maxDistErr="0.000009" units="degrees"/>
location_jts
字段類(lèi)型顯式使用可選的 JTS 集成來(lái)定義一個(gè)點(diǎn),而 location_rpt
字段類(lèi)型不會(huì)這么做。如果您希望對(duì)比簡(jiǎn)單矩形更復(fù)雜的任何內(nèi)容建立索引,則需要使用 JTS 版本。該字段的屬性有助于定義系統(tǒng)的準(zhǔn)確性。在索引時(shí)需要使用這些屬性,因?yàn)?Solr 通過(guò) Lucene 和 Spatial4j 以多種方式編碼數(shù)據(jù),以確??稍谒阉鲿r(shí)高效地使用數(shù)據(jù)。對(duì)于您的應(yīng)用程序,您可能希望對(duì)您的數(shù)據(jù)運(yùn)行一些測(cè)試,以確定要在索引大小、精度和查詢(xún)時(shí)性能上執(zhí)行的權(quán)衡。
此外,Solr Air 應(yīng)用程序中使用的 near
查詢(xún)使用了新的空間查詢(xún)語(yǔ)法(一個(gè) Circle
上的 IsWithin
)來(lái)查找指定的來(lái)源和目標(biāo)機(jī)場(chǎng)附近的機(jī)場(chǎng)。
在這個(gè)介紹 Solr 的一節(jié)最后我才想起,我差點(diǎn)忘記展示更加用戶(hù)友好的現(xiàn)代 Solr 管理 UI 了。這個(gè)新 UI 不僅在外觀上煥然一新,還添加了針對(duì) SolrCloud、文檔添加等的新功能。
對(duì)于初學(xué)者,當(dāng)首次在瀏覽器中打開(kāi) http://localhost:8983/solr/#/ 時(shí),您會(huì)看到一個(gè)儀表板,簡(jiǎn)潔地顯示了 Solr 的許多當(dāng)前狀態(tài):內(nèi)存使用、工作目錄等,如圖 7 所示:
如果在儀表板左側(cè)選擇 Cloud,該 UI 將會(huì)顯示 SolrCloud 的詳細(xì)信息。例如,您會(huì)獲得配置狀態(tài)、活動(dòng)節(jié)點(diǎn)和前導(dǎo)點(diǎn),以及集群拓?fù)浣Y(jié)構(gòu)的可視化的深入信息。圖 8 顯示了一個(gè)示例。請(qǐng)花費(fèi)一點(diǎn)時(shí)間了解一下所有云 UI 選項(xiàng)。(您必須在 SolrCloud 模式下運(yùn)行才能看到它們。)
要介紹的最后一個(gè)未綁定到特定核心/集合/索引的 UI 區(qū)域是 Core Admin 屏幕集合。這些屏幕為核心的管理提供了即指即點(diǎn)式的控制,包括添加、刪除、重新加載和交換核心。圖 9 顯示了 Core Admin UI:
通過(guò)從 Core 列表選擇一個(gè)核心,您可以獲得特定于該核心的信息和統(tǒng)計(jì)數(shù)據(jù)概述。圖 10 顯示了一個(gè)示例:
大多數(shù)針對(duì)核心的功能與 4.x 以前的 UI 的功能類(lèi)似(但是使用起來(lái)更加輕松),除了 Documents 選項(xiàng)之外。您可以使用 Documents 選項(xiàng)直接從 UI 向該集合添加各種格式(JSON、CSV、XML 等)的文檔,如圖 11 所示:
您甚至可上傳富文當(dāng)類(lèi)型,比如 PDF 和 Word。花費(fèi)片刻時(shí)間將一些文檔添加到您的索引中,或者瀏覽其他針對(duì)集合的功能,比如 Query 接口或修改的 Analysis 屏幕。
下一代搜索引擎技術(shù)為用戶(hù)提供了決定如何處理他們的數(shù)據(jù)的權(quán)力。本文詳細(xì)介紹了 Lucene 和 Solr 4 的功能,我還希望您更廣泛地了解了搜索引擎如何解決涉及分析和建議的非基于文本的搜索問(wèn)題。
Lucene 和 Solr 都在不斷演變,這得益于一個(gè)龐大的維護(hù)社區(qū),該社區(qū)由 30 多個(gè)提交者和數(shù)百位貢獻(xiàn)者提供支持。該社區(qū)正在積極開(kāi)發(fā)兩個(gè)主要分支:目前官方發(fā)布的 4.x 分支和主干 分支,它代表著下一個(gè)主要 (5.x) 版本。在官方版本分支上,該社區(qū)致力于實(shí)現(xiàn)向后兼容性,實(shí)現(xiàn)一種專(zhuān)注于當(dāng)前應(yīng)用程序的輕松升級(jí)的增量開(kāi)發(fā)方法。在主干分支上,該社區(qū)在確保與以前版本的兼容性方面受到的限制更少。如果您希望試驗(yàn) Lucene 或 Solr 中的前沿技術(shù),那么請(qǐng)從 Subversion 或 Git 簽出主干分支代碼(參見(jiàn) 參考資料)。無(wú)論您選擇何種路徑,您都可以利用 Lucene 和 Solr 實(shí)現(xiàn)超越純文本搜索的基于搜索的強(qiáng)大分析。
感謝 David Smiley、Erik Hatcher、Yonik Seeley 和 Mike McCandless 提供幫助。
描述 | 名字 | 大小 |
---|---|---|
示例代碼 | code.zip | 60.3MB |
聯(lián)系客服