Tomcat7,solr3.6,mmseg1.8
1:環境的搭建
1:解壓tomcat,solr,mmseg4j
2:複制dist檔案夾下apache-solr.war到tomcat的webapp檔案夾下,修改檔案名為solr(不該也行,這裡修改檔案名友善一會位址欄的輸入)
3:建立solr-tomcat檔案夾作為solr的根目錄
4:tomcat/conf/Catalina/localhost檔案夾(不存在手動建立)下建立solr.xml,檔案内容如下,根據情況,修改相應的路徑
<Context docBase="E:/tomcat7/apache-tomcat-7.0.19/webapps/solr" reloadable="true" >
<Environment name="solr/home" type="java.lang.String" value="E:/solr-tomcat" override="true" />
</Context>
5:複制solr解壓後,example檔案夾下的solr檔案夾到solr-tomcat檔案夾下
6:通路http://localhost:8080/solr/,驗證是否配置成功(通路後,solr-tomcat/solr檔案夾下會多一個data檔案夾)
2:配置檔案的說明
1:apache-tomcat-7.0.19\conf\Catalina\localhost\solr.xml檔案,用來配置solr的根目錄,目前隻用到一次
2:E:\solr-tomcat\solr\solr.xml檔案,目前隻看到在配置多核時用到,後面講
3:E:\solr-tomcat\solr\conf\schema.xml檔案(非常重要)
<fieldType name="string" class="solr.StrField" sortMissingLast="true" />配置域的類型
<field name="name" type="text_general" indexed="true" stored="true"/>配置域,在doc文檔中的用到的field和solrj中用到的域名必須在這裡配置。Index表示是否需要索引,stored是否需要存儲,multiValued表示是否有多個值
<dynamicField name="*_s" type="string" indexed="true" stored="true"/>就是動态比對
<copyField source="name" dest="text"/>在搜尋時可以直接通過“zhang san”來搜尋那麼,不需要在通過“name:zhang san”來搜尋
4:E:\solr-tomcat\solr\conf\solrconfig.xml檔案:緩存,請求的配置,索引的配置
3:浏覽器用戶端的說明
Solr->analyze:分詞
Query String:根據索引搜尋時用。eg:name:zhang san可以通過name來搜尋姓名是zhang san的人。如果配置了copyField也可以直接通過zhang san來搜尋
4:中文分詞的配置
1:解壓mmseg4j,拷貝mmseg4j-all-1.8.5.jar到tomcat\webapp\solr的lib目錄下
2:solr-tomcat\solr下建立dic檔案夾,存放詞庫;拷貝mmseg4j下的words.dic到該目錄下
3:修改schema.xml檔案,添加如下代碼(注意修改路徑)
<!--mmseg4j field types-->
<fieldType name="textComplex" class="solr.TextField" positionIncrementGap="100" >
<analyzer>
<tokenizer class="com.chenlb.mmseg4j.solr.MMSegTokenizerFactory" mode="complex" dicPath="E:/solr-tomcat/solr/dic"/>
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
</fieldType>
<fieldType name="textMaxWord" class="solr.TextField" positionIncrementGap="100" >
<tokenizer class="com.chenlb.mmseg4j.solr.MMSegTokenizerFactory" mode="max-word" dicPath="E:/solr-tomcat/solr/dic"/>
<fieldType name="textSimple" class="solr.TextField" positionIncrementGap="100" >
<tokenizer class="com.chenlb.mmseg4j.solr.MMSegTokenizerFactory" mode="simple" dicPath="E:/solr-tomcat/solr/dic"/>
<field name="simple" type="textSimple" indexed="true" stored="true" multiValued="true"/>
<field name="complex" type="textComplex" indexed="true" stored="true" multiValued="true"/>
<field name="text" type="textMaxWord" indexed="true" stored="true" multiValued="true"/>
<copyField source="simple" dest="text"/>
<copyField source="complex" dest="text"/>
4:測試中文分詞是否起作用
複制一段中文到Field value中;Field選擇name輸入complex,測試分詞
name在使用name(沒有配置中文分詞,使用預設的)再次進行測試
5:多核的配置
1:拷貝example\multicore檔案夾下的core0,core1,solr.xml到solr-tomcat\solr檔案夾下
2:方位http://localhost:8080/solr/
使用浏覽器用戶端建立索引,搜尋
4:建立索引(xml,json,cvs格式的檔案cookbook)
1:複制solr解壓後的,example檔案夾下的exampledocs目錄到solr-tomcat下(裡面包含了一些測試索引用到的檔案)
2:指令行建立索引:E:\solr-tomcat\exampledocs>java -Durl=http://localhost:8080/solr/update -Dcommit=yes -jar post.jar m*.xml,對該檔案夾下所有以m開頭的xml檔案建立索引,此時solr-tomcat\solr\data檔案夾下多了一些檔案,有段檔案,域檔案,索引檔案等
3:通過浏覽器進行搜尋,必須通過一個完整的分詞(一個完整的單詞,不能用a,m,z等搜尋,同時this,that等也不能用于搜尋)
5:更新索引
更新索引一般都是通過删除索引,然後再建立
6:删除索引
Solrj的使用
http://wiki.apache.org/solr/Solrj
private static final String DEFAULT_URL = "http://localhost:8080/solr/";
1:建立索引(如何對一個指定格式的xml建立索引還不清楚)
對檔案進行索引
public void index() throws SolrServerException, IOException {
SolrServer solrServer = new HttpSolrServer(DEFAULT_URL);
SolrInputDocument document = new SolrInputDocument();
document.addField("id", "1"); //id必須有
document.addField("name", "test");
document.addField("path", "測試"); //path需要在schema.xml中定義
solrServer.add(document);
solrServer.commit();
}
對Bean進行索引
public class SolrItem {
/**
* id,對應Solr中記錄的Id
*/
@Field("id")
public String id;
* 員工姓名
@Field("title")
public String empName;
* 員工郵箱
@Field("subject")
public String email;
...
SolrItem item = new SolrItem();
item.setId("1");
item.setEmpName("張三");
item.setEmail("[email protected]");
solrServer.addBean(item);
2:搜尋
public void query(String query) {
SolrParams params = new SolrQuery(query);
try {
QueryResponse response = solrServer.query(params);
SolrDocumentList list = response.getResults();
for (int i = 0; i < list.size(); i++) {
fail(list.get(i));
} catch (SolrServerException e) {
e.printStackTrace();
3:删除索引
public void delete(String params) throws SolrServerException, IOException {
solrServer.deleteByQuery(params);
//solrServer.deleteById(params);
4:高亮顯示
public SolrDocumentList query(String str) {
SolrQuery query = new SolrQuery(str);
//設定高亮,以下兩種方式都行(相當于開啟高亮功能)
//query.setHighlight(true);
query.setParam("hl", "true"); //highlighting
//設定高亮顯示的請求,高亮顯示的内容由該參數決定,但是傳回結果還是由SolrQuery決定
//query.setParam("hl.q", "email:[email protected]");
/*
* 那些字段高亮顯示,可以用空格或者逗号分隔(有一個域的時候正常,兩個及以上沒測試通過)
* 老版本使用query.addHighlightField("name");query.addHighlightField("description");給多個字段開啟高亮功能
query.setParam("hl.fl", "name");
//高亮顯示字段前後添加html代碼
query.setHighlightSimplePre("<font color=\"red\">");
query.setHighlightSimplePost("</font>");
SolrDocumentList list = new SolrDocumentList();
SolrDocument document = null;
QueryResponse response=new QueryResponse();
SolrDocumentList documents = response.getResults();
//第一個Map的鍵是文檔的ID,第二個Map的鍵是高亮顯示的字段名
Map<String, Map<String, List<String>>> map = response.getHighlighting();
for(int i=0;i<documents.size();i++) {
document = documents.get(i);
document.setField("name", map.get(document.getFieldValue("id")).get("name"));
/*document.setField("email", map.get(document.getFieldValue("id")).get("email"));*/
list.add(document);
} catch (Exception e) {
return list;
Solr的其他應用
1:對一篇文章的前100個分詞字建立索引
有時可能需要對某個字段(文章的内容content)的前1000個字元建立索引并存儲,可以在solrconfig.xml中添加<maxFieldLength>1000</maxFieldLength>實作(預設是1萬)。這裡是分詞數量,不是漢字或字母的個數。
2:配置中文分詞後,如果查詢“java程式設計思想”,會自動拆分成java,程式設計,思想3個分詞依次進行查找
3:多條件查詢
可以通過“程式設計 AND empName:XXX”進行查詢,或者“程式設計 OR empName:XXX”等
4:字段當做一個整體,不進行分詞
如果某個字段不需要使用分詞,eg:java程式設計思想,隻有在輸入完成的書名:java程式設計思想才會搜尋出來,可以在書名字段上的type使用不帶分詞的類型(schema.xml中配置)
5:檢索索引中的部分字段
有時索引中可能存放很多資訊,eg:書名,作者,出版時間,ISBN…….;在某次查詢中,我們隻需要搜尋結果書名和作者即可。可以通過如下方式實作
SolrQuery query = new SolrQuery(param);
//傳回的結果
String[] str = {"title", "author"};
query.setFields(str);
6:Solr的分頁
SolrQuery query = new SolrQuery("*:* AND (empName:XXX OR empName:XX)");
query.setHighlight(true);
query.setStart(0);
query.setRows(2);
QueryResponse response = solrServer.query(query);
long totalCount = response.getResults().getNumFound();
totalCount傳回的是滿足條件的總記錄條數,并不一定是0或2
7:solrj高亮顯示時,隻顯示字段部分内容
SolrDocumentList list = response.getResults();
Map<String, Map<String, List<String>>> map = response.getHighlighting();
//對應的高亮字段(假設是content)。在list中顯示正确,map中顯示的隻是content中的一部分。
query.setHighlightFragsize(100000); //可以通過這種方法改變,設定一個比list中,對應content内容大的數字
query.setHighlightSnippets(0);//或者設定高亮片段為0,這樣關鍵字也就不會在高亮顯示
8:搜尋條件的部分關鍵字高亮顯示
有時我們查詢根據條件“java OR (empId:1000 AND empId:1001)”搜尋時,結果如果高亮顯示,可能出現1000,1001數字也會高亮,但是我們隻希望java關鍵字高亮,這個時候可以用下面的方法
query.setParam("hl.q", "lucene solr");隻對lucene和solr關鍵字進行高亮顯示(solr不作為搜尋條件也可以)
9:顯示第一個比對關鍵字附近的部分内容
有時我們需要顯示檢索出内容的一部分(在清單頁,隻需要顯示一個概要資訊),這時候可以通過設定query.setHighlightFragsize(100000);的大小來控制
10:schema檔案,copyField配置
<!-- 感覺使用copyField的作用是。
1:不需要在輸入title:XXX,隻需簡單XXX即可查詢
2:将title,content中輸入的内容全部放到text一個字段上進行,可以簡化查詢不需要過多的判斷
3:需要注意的是:source對應域的類型要和dest域對應的類型相相容
-->
<copyField source="title" dest="complex"/>
<copyField source="content" dest="complex"/>
11:自動補全
搜尋時在title和content上進行搜尋,是以自動補全時要在title和content上同時進行。但是自動補全隻能在一個字段上進行(目前我知道這樣),是以就建立一個新字段searchField=title+”,”+content用來進行自動補全的提示,該字段僅用來索引不需要存儲。
SolrQuery query = new SolrQuery(q);
query.addTermsField(searchField);
query.setTerms(true);
query.setTermsLimit(limit);
query.setTermsLower(pre);
query.setTermsPrefix(pre);
query.setQueryType("/terms");
QueryResponse qr = solrServer.query(query);
TermsResponse resp = qr.getTermsResponse();
List<Term> list = resp.getTerms(searchField);
這種搜尋存在的問題:
1: q:empName:XXX AND projecteId:19 pre:lucen 在搜尋時,傳回的TermsResponse結果隻應用了pre一個條件
2: title,content無法配置copyField字段使用complex(原因及解決辦法沒找到)
解決方法:改用Facet替換Term
SolrQuery query = new SolrQuery(q);
query.setFacet(true);
query.addFacetField(searchField);
query.setFacetLimit(limit);
query.setFacetPrefix(pre);
QueryResponse qr = solrServer.query(query);
List<FacetField> fss = qr.getFacetFields();
FacetField ff = fss.get(0);
return ff.getValues();
傳回的fss結果仍然是根據pre一個條件傳回的結果集,但是不滿足條件query的結果集中,對應的count為0,即出現了0次
12:solr删除索引後,索引檔案還存在,但是搜尋結果已經不存在
13:添加tomcat驗證,防止使用者直接通過位址欄通路solr,進行修改删除索引
1:修改tomcat-user.xml檔案
<role rolename="tomcat"/>
<role rolename="role1"/>
<role rolename="manager"/>
<role rolename="admin"/>
<role rolename="manager-gui"/>
<user username="tomcat" password="tomcat" roles="tomcat"/>
<user username="both" password="tomcat" roles="tomcat,role1"/>
<user username="role1" password="tomcat" roles="role1"/>
<user username="zhchx" password="zhchx" roles="admin,manager,manager-gui"/>
2:修改solr的web.xml檔案,添加如下代碼,對所有的請求,都需要tomcat使用者及密碼的驗證
<security-constraint>
<web-resource-collection>
<web-resource-name>solr</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<description>This applies only to the "tomcat" security role</description>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
<security-role>
<role-name>admin</role-name>
</security-role>
3:使用該方法後,通過solrj也不能直接通路,修改如下
String url = PropertiesSon.getText("solr.serverUrl");
String username = PropertiesSon.getText("solr.username");
String password = PropertiesSon.getText("solr.password");
String host = PropertiesSon.getText("solr.host");
int port = Integer.parseInt(PropertiesSon.getText("solr.port"));
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.getCredentialsProvider().setCredentials(
new AuthScope(host, port),
new UsernamePasswordCredentials(username, password));
solrServer = new HttpSolrServer(url, httpclient);
4:使用該方法建立時,删除添加索引報錯“Cannot retry request with a non-repeatable request entity.”
修改方法:url用http://username:[email protected]:8081/solr取代http://10.1.20.57:8081/solr(httpclient使用 4.2是時正常,使用4.1時,在删除新增索引仍然會報上面的錯誤)