1. 程式人生 > >solr的認識、安裝和使用

solr的認識、安裝和使用

一、solr的大概認識

(1)在網際網路專案裡面,絕大部分是用全文檢索伺服器,
lucense(基於java的全文檢索api)和solr(基於lucense的全文檢索伺服器)都可以實現。用lucense需要自己來管理維護索引庫,進行索引庫的優化,快取的新增。而solr配置一下就好了,比較方便。
(2)solr本質上是一個war包,然後部署到servlet容器中,容器你可以選擇用tomcat,也可以選擇更加輕量級的jetty

二、solr安裝

(1)安裝jdk(省略)
(2)下載 solr-4.10.3.tgz.tgz並解壓
(3)安裝tomcat(省略)
(4)拷貝solr的war包到tomcat下

[[email protected] apache-tomcat-7.0.47]# cp /usr/solr/solr-4.10.3/dist/solr-4.10.3.war webapps/solr.war

(5)啟動tomcat自動解壓縮war包:

[[email protected] apache-tomcat-7.0.47]# bin/startup.sh

(6)檢視控制檯,檢查tomcat啟動情況:

[[email protected] apache-tomcat-7.0.47]# tail -f logs/catalina.out

(7)關閉tomcat

[[email protected] apache-tomcat-7.0.47]# bin/shutdown.sh

(8)刪除war包

[[email protected] apache-tomcat-7.0.47]# rm -f webapps/solr.war

(9)把一些jar包放到solr工程下面去:

[[email protected] apache-tomcat-7.0.47]# cp /usr/solr/solr-4.10.3/example/lib/ext/* webapps/solr/WEB-INF/lib/

(10)配置solrhome

[[email protected]
solr-4.10.3]# cp -r example/solr /usr/solr/solrhome [[email protected] apache-tomcat-7.0.47]# cd webapps/solr/WEB-INF/ [[email protected] WEB-INF]# vim web.xml

修改solr/home的地址,並且去掉註釋
在這裡插入圖片描述
(11)再次開啟tomcat

[[email protected] apache-tomcat-7.0.47]# bin/startup.sh

(12)在Windows那邊訪問solr
http://192.168.25.128:8080/solr/
在這裡插入圖片描述
在這裡插入圖片描述

三、solr的深度認識

使用者可以通過http請求,向搜尋引擎伺服器提交一定格式的XML檔案,生成索引;也可以通過Http Get操作提出查詢請求,並得到XML格式的返回結果。

四、solr的使用

(1)由於我們用到中文,所以需要中文分析器,這裡我用IK Analyzer 2012FF_hf1,
下載好IK Analyzer 2012FF_hf1檔案後,安裝步驟:
<1>拷貝IKAnalyzer2012FF_u1.jar到tomcat的solr專案下的lib中:

[[email protected] apache-tomcat-7.0.47]# cd webapps/solr/WEB-INF/lib
[[email protected] lib]# cp /usr/solr/IK_Analyzer_2012FF_hf1/IKAnalyzer2012FF_u1.jar .

<2>拷貝三個檔案到tomcat的solr專案下的classes檔案中:

[[email protected] lib]# cd ..
[[email protected] WEB-INF]# mkdir classes
[[email protected] IK_Analyzer_2012FF_hf1]# cp ext_stopword.dic IKAnalyzer.cfg.xml mydict.dic /usr/tomcat/apache-tomcat-7.0.47/webapps/solr/WEB-INF/classes

<3>在solrhome裡面的schema.xml定義一個fieldtype,來指定IK分析器。

  <fieldType name="text_ik" class="solr.TextField">
    <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>
  </fieldType>

(2)同時在schema.xml指定好業務域 field name…,由於solr本身就定義了id,所以我們用solr的id來儲存我們要的id就可以了。
注意:string型別的是不可拆分的,而TextField型別的是可拆分的

<field name="item_title" type="text_ik" indexed="true" stored="true"/>
<field name="item_sell_point" type="text_ik" indexed="true" stored="true"/>
<field name="item_price"  type="long" indexed="true" stored="true"/>
<field name="item_image" type="string" indexed="false" stored="true" />
<field name="item_category_name" type="string" indexed="true" stored="true" />
<field name="item_desc" type="text_ik" indexed="true" stored="false" />

(3)同時在schema.xml配置複製域,就是說你找一個商品的時候,可以在item_keywords中的四個域中找

<field name="item_keywords" type="text_ik" indexed="true" stored="false" multiValued="true"/>
<copyField source="item_title" dest="item_keywords"/>
<copyField source="item_sell_point" dest="item_keywords"/>
<copyField source="item_category_name" dest="item_keywords"/>
<copyField source="item_desc" dest="item_keywords"/>

(4)啟動solr看看業務域是否能用

[[email protected] apache-tomcat-7.0.47]# bin/startup.sh

進入http://192.168.25.128:8080/solr/裡面的collection1的Analyse ,選擇一個域,比如:
在這裡插入圖片描述

五、用java程式碼增刪data到solr中

(1)導包

<!-- 新增solrJ的依賴 -->
		<dependency>
			<groupId>org.apache.solr</groupId>
			<artifactId>solr-solrj</artifactId>
		</dependency>

(2)測試一下

import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.junit.Test;

public class TestSolrJ {

	@Test
	public void testAddDocument() throws Exception {
		//建立一個SolrServer物件。建立一個HttpSolrServer物件
		//需要指定solr服務的url
		SolrServer solrServer = new HttpSolrServer("http://192.168.25.128:8080/solr/collection1");
		//建立一個文件物件SolrInputDocument
		SolrInputDocument document = new SolrInputDocument();
		//向文件中新增域,必須有id域,域的名稱必須在schema.xml中定義
		document.addField("id", "1234");
		document.addField("item_title", "測試商品2");
		document.addField("item_price", 1000);
		//把文件物件寫入索引庫
		solrServer.add(document);
		//提交
		solrServer.commit();
	}
	
	@Test
	public void deleteDocumentById() throws Exception {
		SolrServer solrServer = new HttpSolrServer("http://192.168.25.128:8080/solr/collection1");
		solrServer.deleteById("123");
		//提交
		solrServer.commit();
	}
	
	@Test
	public void deleteDocumentByQuery() throws Exception {
		SolrServer solrServer = new HttpSolrServer("http://192.168.25.128:8080/solr/collection1");
		solrServer.deleteByQuery("item_title:測試商品3");
		solrServer.commit();
	}
}
	

(3)實際開發中匯入文件到solr的步驟

<1>定義一個 (將資料庫的部分資料匯入到solr的data中的)介面

import com.wine.common.pojo.WineResult;
public interface SearchItemService {
	WineResult importItemsToIndex();
}

<2>實現這個介面

@Service
public class SearchItemServiceImpl implements SearchItemService {

	@Autowired
	private SearchItemMapper searchItemMapper;
	@Autowired
	private SolrServer solrServer;
	
	@Override
	public WineResult importItemsToIndex() {
		try {
			//1、先查詢所有商品資料
			List<SearchItem> itemList = searchItemMapper.getItemList();
			//2、遍歷商品資料新增到索引庫
			for (SearchItem searchItem : itemList) {
				//建立文件物件
				SolrInputDocument document = new SolrInputDocument();
				//向文件中新增域
				document.addField("id", searchItem.getId());
				document.addField("item_title", searchItem.getTitle());
				document.addField("item_sell_point", searchItem.getSell_point());
				document.addField("item_price", searchItem.getPrice());
				document.addField("item_image", searchItem.getImage());
				document.addField("item_category_name", searchItem.getCategory_name());
				document.addField("item_desc", searchItem.getItem_desc());
				//把文件寫入索引庫
				solrServer.add(document);
			}
			//3、提交
			solrServer.commit();
		} catch (Exception e) {
			e.printStackTrace();
			return WineResult.build(500, "資料匯入失敗");
		}
		//4、返回新增成功
		return WineResult.ok();
	}

}

<3>solr連線檔案applicationContext-solr.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
	http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">
	
	<!-- 單機版solr的連線 -->
	<bean id="httpSolrServer" class="org.apache.solr.client.solrj.impl.HttpSolrServer">
		<constructor-arg name="baseURL" value="http://192.168.25.128:8080/solr/collection1"/>
	</bean>
	<!-- 叢集版solr連線 -->
	<!-- <bean id="cloudSolrServer" class="org.apache.solr.client.solrj.impl.CloudSolrServer">
		<constructor-arg name="zkHost" value="192.168.25.128:2181,192.168.25.128:2182,192.168.25.128:2183"></constructor-arg>
		<property name="defaultCollection" value="collection2"/>
	</bean> -->
	
</beans>

六、實際開發中實現搜尋功能步驟

<1>首先測試一下,輸入測試商品,看看搜尋出什麼東西:

@Test
	public void searchDocumet() throws Exception {
		//建立一個SolrServer物件
		SolrServer solrServer = new HttpSolrServer("http://192.168.25.128:8080/solr/collection1");
		//建立一個SolrQuery物件
		SolrQuery query = new SolrQuery();
		//設定查詢條件、過濾條件、分頁條件、排序條件、高亮
		//query.set("q", "*:*");
		query.setQuery("測試商品");
		//分頁條件
		query.setStart(0);
		query.setRows(10);
		//設定預設搜尋域
		query.set("df", "item_keywords");
		//設定高亮
		query.setHighlight(true);
		//高亮顯示的域
		query.addHighlightField("item_title");
		query.setHighlightSimplePre("<div>");
		query.setHighlightSimplePost("</div>");
		
		//執行查詢,得到一個Response物件
		QueryResponse response = solrServer.query(query);
		//取查詢結果
		SolrDocumentList solrDocumentList = response.getResults();
		//取查詢結果總記錄數
		System.out.println("查詢結果總記錄數:" + solrDocumentList.getNumFound());
		for (SolrDocument solrDocument : solrDocumentList) {
			System.out.println(solrDocument.get("id"));
			//取高亮顯示
			Map<String, Map<String, List<String>>> highlighting = response.getHighlighting();
			List<String> list = highlighting.get(solrDocument.get("id")).get("item_title");
			String itemTitle = "";
			if (list != null && list.size() >0) {
				itemTitle = list.get(0);
			} else {
				itemTitle = (String) solrDocument.get("item_title");
			}
			System.out.println(itemTitle);
			System.out.println(solrDocument.get("item_sell_point"));
			System.out.println(solrDocument.get("item_price"));
			System.out.println(solrDocument.get("item_image"));
			System.out.println(solrDocument.get("item_category_name"));
			System.out.println("=============================================");
		}
		
	}

結果:(注意:solr安裝匹配次數多的來排序)

查詢結果總記錄數:6
123456
<div>測試</div><div>商品</div>2
null
1000
null
null
=============================================
1
<div>測試</div>2<div>商品</div>
null
1000
null
null
=============================================
2
2<div>商品</div><div>測試</div>
null
1000
null
null
=============================================
7
66<div>測試</div>66<div>商品</div>
null
1000
null
null
=============================================
5
2<div>測試</div>
null
1000
null
null
=============================================
6
2<div>商品</div>
null
1000
null
null
=============================================

<2>具體程式碼實現:
新增一個訪問solr的dao:

/**
 * 查詢索引庫商品dao
 */
@Repository
public class SearchDao {
	
	@Autowired
	private SolrServer solrServer;
	/**
	SearchResult 這個pojo類裡面的資料:
	private long totalPages;
	private long recordCount;
	private List<SearchItem> itemList;
	**/
	public SearchResult search(SolrQuery query) throws Exception{
		//根據query物件進行查詢
		QueryResponse response = solrServer.query(query);
		//取查詢結果
		SolrDocumentList solrDocumentList = response.getResults();
		//取查詢結果總記錄數
		long numFound = solrDocumentList.getNumFound();
		SearchResult result = new SearchResult();
		result.setRecordCount(numFound);
		List<SearchItem> itemList = new ArrayList<>();
		//把查詢結果封裝到SearchItem物件中
		for (SolrDocument solrDocument : solrDocumentList) {
			SearchItem item = new SearchItem();
			item.setCategory_name((String) solrDocument.get("item_category_name"));
			item.setId((String) solrDocument.get("id"));
			//取一張圖片
			String image = (String) solrDocument.get("item_image");
			if (StringUtils.isNotBlank(image)) {
				image = image.split(",")[0];
			}
			item.setImage(image);
			item.setPrice((long) solrDocument.get("item_price"));
			item.setSell_point((String) solrDocument.get("item_sell_point"));
			//取高亮顯示
			Map<String, Map<String, List<String>>> highlighting = response.getHighlighting();
			List<String> list = highlighting.get(solrDocument.get("id")).get("item_title");
			String title = "";
			if (list != null && list.size() > 0) {
				title = list.get(0);
			} else {
				title = (String) solrDocument.get("item_title");
			}
			item.setTitle(title);
			//新增到商品列表
			itemList.add(item);
		}
		//把結果新增到SearchResult中
		result.setItemList(itemList);
		//返回
		return result;
	}
}

新增呼叫dao的service類:

/**
 * 搜尋服務功能實現
 */
@Service
public class SearchServiceImpl implements SearchService {

	@Autowired
	private SearchDao searchDao;
	
	@Override
	public SearchResult search(String queryString, int page, int rows) throws Exception {
		//根據查詢條件拼裝查詢物件
		//建立一個SolrQuery物件
		SolrQuery query = new SolrQuery();
		//設定查詢條件
		query.setQuery(queryString);
		//設定分頁條件
		if (page < 1) page =1;
		query.setStart((page - 1) * rows);
		if (rows < 1) rows = 10;
		query.setRows(rows);
		//設定預設搜尋域
		query.set("df", "item_title");
		//設定高亮顯示
		query.setHighlight(true);
		query.addHighlightField("item_title");
		query.setHighlightSimplePre("<font color='red'>");
		query.setHighlightSimplePost("</font>");
		//呼叫dao執行查詢
		SearchResult searchResult = searchDao.search(query);
		//計算查詢結果的總頁數
		long recordCount = searchResult.getRecordCount();
		long pages =  recordCount / rows;
		if (recordCount % rows > 0) {
			pages++;
		}
		searchResult.setTotalPages(pages);
		//返回結果
		return searchResult;
	}

}

控制層:

@Controller
public class SearchController {
	
	@Autowired
	private SearchService searchService;
	
	@Value("${SEARCH_RESULT_ROWS}")
	private Integer SEARCH_RESULT_ROWS;

	@RequestMapping("/search")
	public String search(@RequestParam("q")String queryString, 
			@RequestParam(defaultValue="1")Integer page, Model model) throws Exception {
		//int a = 1/0;
		//呼叫服務執行查詢
		//把查詢條件進行轉碼,解決get亂碼問題
		queryString = new String(queryString.getBytes("iso8859-1"), "utf-8");
		SearchResult searchResult = searchService.search(queryString, page, SEARCH_RESULT_ROWS);
		//把結果傳遞給頁面
		model.addAttribute("query", queryString);
		model.addAttribute("totalPages", searchResult.getTotalPages());
		model.addAttribute("itemList", searchResult.getItemList());
		model.addAttribute("page", page);

		//返回邏輯檢視
		return "search";
		
	}
}