在本文中,咱們將探討一個Apache Solr搜索引擎中的基本概念 - 全文搜索。html
Apache Solr是一個開源框架,旨在處理數百萬的文檔。咱們將經過使用Java庫- SolrJ的示例來介紹它的核心功能。git
因爲Solr是開源的 - 咱們能夠簡單地下載二進制文件並在咱們的應用程序中單獨啓動服務器。github
要與服務器通訊,咱們將爲SolrJ客戶端定義Maven依賴項:數據庫
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
<version>6.4.2</version>
</dependency>複製代碼
你將在這兒找到最新的依賴。apache
爲了索引和搜索數據,咱們須要建立一個core
以及一個item
來索引數據。緩存
在咱們這樣作以前,咱們須要在服務器上爲數據創建索引,以便它能夠搜索。服務器
咱們能夠經過許多不一樣的方式爲數據創建索引。咱們可使用數據導入處理程序直接從關係數據庫導入數據,使用Apache Tika經過Solr Cell上傳數據或使用索引處理程序上傳XML/ XSLT,JSON和CSV數據。框架
咱們能夠經過建立SolrInputDocument將數據索引到核心。首先,咱們須要使用咱們的數據填充文檔,而後只調用SolrJ的API爲文檔創建索引:maven
SolrInputDocument doc = new SolrInputDocument();
doc.addField("id", id);
doc.addField("description", description);
doc.addField("category", category);
doc.addField("price", price);
solrClient.add(doc);
solrClient.commit();複製代碼
請注意,id對於不一樣的item應該是惟一的。已創建索引的文檔根據ID更新該文檔。ide
SolrJ提供了用於索引Java bean的API。要爲bean創建索引,咱們須要使用@Field對其進行註解::
public class Item {
@Field
private String id;
@Field
private String description;
@Field
private String category;
@Field
private float price;
}複製代碼
一旦咱們添加bean,索引就已經創建好:
solrClient.addBean(item);
solrClient.commit();複製代碼
搜索是Solr最強大的功能。咱們一旦在存儲庫中創建索引文檔,咱們就能夠根據關鍵字,短語,日期範圍等進行搜索。結果按相關性(得分)排序。
服務器公開用於搜索操做的API。咱們能夠調用/select或/query程序處理請求。
咱們來作一個簡單的搜索:
SolrQuery query = new SolrQuery();
query.setQuery("brand1");
query.setStart(0);
query.setRows(10);
QueryResponse response = solrClient.query(query);
List<Item> items = response.getBeans(Item.class);複製代碼
SolrJ將在其對服務器的請求內部使用主查詢參數q。返回記錄的數量爲10,未指定start和rows參數時,從0開始索引。
上面的搜索查詢將查找在其任何索引字段中包含完整單詞「brand1」的任何文檔。請注意,簡單搜索不區分大小寫。
讓咱們看另外一個例子。咱們想要搜索任何包含「rand」的單詞,該單詞以任意數量的字符開頭,而且只以一個字符結尾。咱們能夠在查詢中使用*和?通配符:
query.setQuery("*rand?");複製代碼
Solr查詢還支持相似SQL中的布爾操做:
query.setQuery("brand1 AND (Washing OR Refrigerator)");複製代碼
全部布爾運算符必須所有大寫;查詢解析器支持的是AND,OR,NOT,+和 - 。
更重要的是,若是咱們想要搜索特定字段而不是全部索引字段,咱們能夠在查詢中指定這些字段:
query.setQuery("description:Brand* AND category:*Washing*");複製代碼
到目前爲止,咱們只用代碼在索引字段中查找關鍵字。咱們還能夠對索引字段進行短語搜索:
query.setQuery("Washing Machine");複製代碼
當咱們有一個像「Washing Machine」這樣的短語時,Solr的標準查詢解析器將其解析爲「Washing OR Machine」。要搜索整個短語,咱們只能在雙引號內添加表達式:
query.setQuery("\"Washing Machine\"");複製代碼
咱們可使用鄰近搜索來查找特定距離內的單詞。若是咱們想要找到至少相距兩個單詞的短語,咱們可使用如下查詢:
query.setQuery("\"Washing equipment\"~2");複製代碼
範圍查詢容許獲取其字段在特定範圍之間的文檔。假設咱們想要找到價格在100到300之間的商品:
query.setQuery("price:[100 TO 300]");複製代碼
上面的查詢將找到價格在100到300之間的全部元素,包括100和300。咱們可使用「}」和「{」來排除終點:
query.setQuery("price:{100 TO 300]");複製代碼
篩選查詢可用於限制可返回的結果的超集。過濾查詢不會影響排序:
SolrQuery query = new SolrQuery();
query.setQuery("price:[100 TO 300]");
query.addFilterQuery("description:Brand1","category:Home Appliances");複製代碼
一般,過濾器查詢將包含經常使用查詢。因爲它們一般是可重用的,所以它們被緩存以使搜索更有效。
Faceting有助於將搜索結果安排到組計數中。咱們可使用字段,查詢或範圍。
例如,咱們但願在搜索結果中獲取聚合的類別計數。咱們能夠在查詢中添加類別字段:
query.addFacetField("category");
QueryResponse response = solrClient.query(query);
List<Count> facetResults = response.getFacetField("category").getValues();複製代碼
facetResults將包含結果中每一個類別的計數。
當咱們想要返回子查詢的計數時,查詢切面很是有用:
query.addFacetQuery("Washing OR Refrigerator");
query.addFacetQuery("Brand2");
QueryResponse response = solrClient.query(query);
Map<String,Integer> facetQueryMap = response.getFacetQuery();複製代碼
所以,facetQueryMap將具備facet查詢的計數。
範圍切面用於獲取搜索結果中的範圍計數。如下查詢將返回介於100和251之間的價格範圍計數,其間隔爲25:
query.addNumericRangeFacet("price", 100, 275, 25);
QueryResponse response = solrClient.query(query);
List<RangeFacet> rangeFacets = response.getFacetRanges().get(0).getCounts();複製代碼
除數值範圍外,Solr還支持日期範圍,區間切面和支點切面。
咱們可能但願在搜索結果中突出顯示搜索查詢中的關鍵字。這對於更好地瞭解結果很是有幫助。讓咱們索引一些文檔並定義要突出顯示的關鍵字:
itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f);
itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f);
itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "Home Appliances", 200f);
itemSearchService.index("hm0004", "Brand2 Dishwasher", "Washing equipments", 250f);
SolrQuery query = new SolrQuery();
query.setQuery("Appliances");
query.setHighlight(true);
query.addHighlightField("category");
QueryResponse response = solrClient.query(query);
Map<String, Map<String, List<String>>> hitHighlightedMap = response.getHighlighting();
Map<String, List<String>> highlightedFieldMap = hitHighlightedMap.get("hm0001");
List<String> highlightedList = highlightedFieldMap.get("category");
String highLightedText = highlightedList.get(0);複製代碼
咱們獲取到的highLightedText爲"Home Appliances
"。請注意,搜索關鍵字Appliances被標記。 Solr使用的默認突出顯示標記是
,但咱們能夠經過設置pre和post標記來更改它:
query.setHighlightSimplePre("<strong>");
query.setHighlightSimplePost("</strong>");複製代碼
Solr支持的一個重要功能是建議。若是查詢中的關鍵字包含拼寫錯誤,或者咱們建議自動填寫搜索關鍵字,咱們可使用建議功能。
標準搜索處理程序不包括拼寫檢查組件;它必須手動配置。有三種方法能夠作到這一點。您能夠在官方wiki page中找到配置詳細信息。在咱們的示例中,咱們將使用IndexBasedSpellChecker,它使用索引數據進行關鍵字拼寫檢查。
讓咱們搜索拼寫錯誤的關鍵字:
query.setQuery("hme");
query.set("spellcheck", "on");
QueryResponse response = solrClient.query(query);
SpellCheckResponse spellCheckResponse = response.getSpellCheckResponse();
Suggestion suggestion = spellCheckResponse.getSuggestions().get(0);
List<String> alternatives = suggestion.getAlternatives();
String alternative = alternatives.get(0);複製代碼
關鍵字「hme」的預期替代應該是「home」,由於咱們的索引包含術語「home」。請注意,必須在執行搜索以前激活拼寫檢查。
咱們可能但願得到不完整關鍵字的建議以協助搜索。 Solr的建議組件必須手動配置。您能夠在其官方wiki page中找到配置詳細信息。
咱們已經配置了一個名爲/suggest的請求處理程序來處理建議。讓咱們獲得關鍵字「Hom」的建議:
SolrQuery query = new SolrQuery();
query.setRequestHandler("/suggest");
query.set("suggest", "true");
query.set("suggest.build", "true");
query.set("suggest.dictionary", "mySuggester");
query.set("suggest.q", "Hom");
QueryResponse response = solrClient.query(query);
SuggesterResponse suggesterResponse = response.getSuggesterResponse();
Map<String,List<String>> suggestedTerms = suggesterResponse.getSuggestedTerms();
List<String> suggestions = suggestedTerms.get("mySuggester");複製代碼
列表建議應包含全部單詞和短語。請注意,咱們在配置中配置了名爲mySuggester的建議器。
本文簡要介紹了搜索引擎的Solr功能和特性。
咱們談到了許多功能,但這些固然只是表現了咱們可使用高級和成熟的搜索服務器(如Solr)所作的事情。
這裏使用的示例能夠在GitHub上使用。