Sorl的简单入门

本文介绍了Solr的基本概念和安装配置步骤,包括设置Solrhome、配置Core以及理解配置文件。重点讲解了如何解决Solr5.5与IK分词器的兼容性问题,通过修改源码实现对Lucene5的支持。同时,文章还提到了Solrj客户端的使用和Solr的一些高级查询技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 . 什么是solr

    solr是以lucene为内核开发的企业级搜索应用  应用程序可以通过http请求方式来提交索引,查询索引,提供了比lucene更丰富的查询语言,是一个高性能,高可用环境全文搜索引擎

二 .solr安装配置

1.下载solr安装包solr所有版本 (http://archive.apache.org/dist/lucene/solr/) 这里下载 solr-5.5.4

     2.安装 解压将solr-5.5.4\server\solr-webapp下的webapp 拷贝到tomcat\webapps目录下 改名为solr 启动tomcat直接访问 会出现缺少SLF4j包异常 应该去 应该去 解压包 /server/lib/ext下找到并拷贝到 tomcat/solr/lib目录下  然后重启  继续访问 出现以下错误 

java.lang.NoSuchMethodError: javax.servlet.ServletInputStream.isFinished()Z  
    org.apache.solr.servlet.SolrDispatchFilter.consumeInputFully(SolrDispatchFilter.java:284)  
    org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:274)  
    org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:208) 
明显是Servlet版本不一致  tomcat6不支持solr5.54 加大tomcat版本 tomcat7也不支持 换成tomcat8  启动后访问 依然错误

org.apache.solr.common.SolrException: Error processing the request. CoreContainer is either not initialized or shutting down.  
    org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:217)  
    org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:208) 
是因为需要配置solrhome和solrhome的配置环境

3.配置solrhome

 找到 tomcat\solr\WEB-INF\web.xml 编辑  找到以下这段(配置solrhome)  去掉注释 将第二个参数配置为本地创建的一个新目录即可 

<env-entry>  
   <env-entry-name>solr/home</env-entry-name>  
   <env-entry-value>F:\solrHome</env-entry-value>  
   <env-entry-type>java.lang.String</env-entry-type>  
</env-entry>  
到solr解压包/server/solr目录拷贝所有文件到 以上web.xml指定的路径F:\solrHom下 重启tomcat 访问

   http://localhost:8080/solor/index.html  或者 http://localhost:8080/solr/admin.html  



4.配置core(core类似于数据库可以插入多个document(数据库表行)每个document拥有多个 field 数据库的列)

   solrhome下新建一个core目录  比如core1

   拷贝 solr解压包下\server\solr\configsets\basic_configs\conf到新建目录 core1中

  进入solr管理网页 点击 core admin 添加该core1


 点击Add core后 成功后 检查 core目录 发现多了 core.properties和data两个资源

5.配置文件理解

 core/conf目录下的两个配置文件非常重要 

    managed-schema 主要用于配置 可以提交到该core的所有field定义,field的类型定义,唯一标识符等

    常用配置如下:

定义字段 _version_ 类型为long  indexed="true" 会进行分词索引  stored="true"表示存储到磁盘  
<field name="_version_" type="long" indexed="true" stored="true"/>  
定义字段 id required="true" 表示所有的document必须添加id字段 multiValued="false" 表示是否是多值字段  
<field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />   
定义动态字段 所以_i结尾的字段都可以写入到当前的core  
<dynamicField name="*_i"  type="int"    indexed="true"  stored="true"/>  
定义唯一标识符的字段  
<uniqueKey>id</uniqueKey>  
定义字段类型的别名  
<fieldType name="string" class="solr.StrField" sortMissingLast="true" /> 
  solrconfig.xml 主要用于配置solor的主要配置信息 比如lucene版本 缓存 数据目录 请求路径映射 等 

表示lucene版本  
<luceneMatchVersion>5.5.4</luceneMatchVersion>  
表示数据目录 默认是data目录  
<dataDir>${solr.data.dir:}</dataDir>   
自动提交配置  
<autoCommit>   
       当超过15000ms后自动提交所有数据  
       <maxTime>${solr.autoCommit.maxTime:15000}</maxTime>   
       是否马上就可以查询到  
       <openSearcher>false</openSearcher>   
</autoCommit>  
表示当路径为 /select时查询所有的数据  
<requestHandler name="/select" class="solr.SearchHandler">  
    <!-- default values for query parameters can be specified, these  
         will be overridden by parameters in the request  
      -->  
     <lst name="defaults">  
       <str name="echoParams">explicit</str>  
       <int name="rows">10</int>  
     </lst>  
</requestHandler>  
 尝试在界面上添加数据和查询数据

 添加数据




查询结果

查询的参数列表

  q表示查询的条件  字段名:值的格式

  fq表示filter query 过滤条件 和q是and的关系支持各种逻辑运算符 (参考https://cwiki.apache.org/confluence/display/solr/The+Standard+Query+Parser)

  sort表示排序 的字段  字段名 asc|desc 

  start 表示从第几行开始  rows表示查询的总行数

  fl表示查询显示的列 比如只需要查询 name_s,sex_i 这两列 使用,隔开

  df表示默认的查询字段 一般不设置

  Raw Query Parameters表示原始查询字段 可以使用 start=0&rows=10这种url的方式传入参数

  wt(write type)表示写入的格式 可以使用json和xml

  shards 多核同时搜索 solrhome拷贝core1为core2  管理平台添加core   设置参数为 路径,路径来设置需要搜索的核

String shards = "localhost:8080/solr/core1,localhost:8080/solr/core2";   
query.set("shards", shards);
 其他参考(https://cwiki.apache.org/confluence/display/solr/Common+Query+Parameters)
 5.配置中文分词器

默认solr 没有使用中文分词器  所有搜索的词 都是整个句子就是一个词 搜索时 将单词全部写入才能搜索或者使用* 需要配置中文分词器

目前比较好用的分词器 是IK  2012年停更 只支持到 Lucene4.7 所有 solr5.5 需要lucene5支持  需要修改部分源码来支持solr5.5

 找到 IKAnalyzer类   需要重写  protected TokenStreamComponents createComponents(String fieldName) 方法

 找到 IKTokenizer类 需要重写构造方法  public IKTokenizer(Reader in, boolean useSmart) 为  public IKTokenizer(boolean useSmart) {

 在任意项目中 使用maven 引用lucene5 和ik

<dependency>  
          <groupId>org.apache.lucene</groupId>  
          <artifactId>lucene-core</artifactId>  
          <version>5.3.1</version>  
        </dependency>  
        <dependency>  
            <groupId>com.janeluo</groupId>  
            <artifactId>ikanalyzer</artifactId>  
            <version>2012_u6</version>  
            <exclusions>  
                <exclusion>  
                    <groupId>org.apache.lucene</groupId>  
                     <artifactId>lucene-core</artifactId>  
                </exclusion>  
            </exclusions>  
        </dependency>  
在项目中 添加完整的包名和类名 和 ik中一致 拷贝源代码

代码修改对应的方法即可

IKAnalyzer

/**  
  
 *  
 */  
package org.wltea.analyzer.lucene;  
  
import java.io.Reader;  
  
import org.apache.lucene.analysis.Analyzer;  
import org.apache.lucene.analysis.Tokenizer;  
  
/**  
 */  
public final class IKAnalyzer extends Analyzer {  
  
  private boolean useSmart;  
  
  public boolean useSmart() {  
    return useSmart;  
  }  
  
  public void setUseSmart(boolean useSmart) {  
    this.useSmart = useSmart;  
  }  
  
  /**  
  
   */  
  public IKAnalyzer() {  
    this(false);  
  }  
  
  /**  
   */  
  public IKAnalyzer(boolean useSmart) {  
    super();  
    this.useSmart = useSmart;  
  }  
  
  /**这里就去掉了 Reader的一个参数  
   */  
  @Override  
  protected TokenStreamComponents createComponents(String fieldName) {  
    Tokenizer _IKTokenizer = new IKTokenizer(this.useSmart());  
    return new TokenStreamComponents(_IKTokenizer);  
  }  
  
}  
IKTokenizer

/**  
 *   
 */  
package org.wltea.analyzer.lucene;  
  
import java.io.IOException;  
import java.io.Reader;  
  
import org.apache.lucene.analysis.Tokenizer;  
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;  
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;  
import org.apache.lucene.analysis.tokenattributes.TypeAttribute;  
  
import org.wltea.analyzer.core.IKSegmenter;  
import org.wltea.analyzer.core.Lexeme;  
  
  
public final class IKTokenizer extends Tokenizer {  
  
  
  private IKSegmenter _IKImplement;  
  
  
  private final CharTermAttribute termAtt;  
  
  private final OffsetAttribute offsetAtt;  
  
  private final TypeAttribute typeAtt;  
  
  private int endPosition;  
  
  //去掉了其中Reader的第一个构造参数  
  public IKTokenizer(boolean useSmart) {  
    super();//去掉super中的构造参数  
    offsetAtt = addAttribute(OffsetAttribute.class);  
    termAtt = addAttribute(CharTermAttribute.class);  
    typeAtt = addAttribute(TypeAttribute.class);  
    _IKImplement = new IKSegmenter(input, useSmart);  
  }  
  
   
  @Override  
  public boolean incrementToken() throws IOException {  
  
    clearAttributes();  
    Lexeme nextLexeme = _IKImplement.next();  
    if (nextLexeme != null) {  
  
      termAtt.append(nextLexeme.getLexemeText());  
     
      termAtt.setLength(nextLexeme.getLength());  
        
      offsetAtt.setOffset(nextLexeme.getBeginPosition(), nextLexeme.getEndPosition());  
     
      endPosition = nextLexeme.getEndPosition();  
    
      typeAtt.setType(nextLexeme.getLexemeTypeString());  
  
      return true;  
    }  
  
    return false;  
  }  
  
  /*  
   * (non-Javadoc)  
   * @see org.apache.lucene.analysis.Tokenizer#reset(java.io.Reader)  
   */  
  @Override  
  public void reset() throws IOException {  
    super.reset();  
    _IKImplement.reset(input);  
  }  
  
  @Override  
  public final void end() {  
    // set final offset  
    int finalOffset = correctOffset(this.endPosition);  
    offsetAtt.setOffset(finalOffset, finalOffset);  
  }  
}  
将编译好的class文件替换原始jar包即可,将架包加入到\apache-tomcat-8.0.44\webapps\solr\WEB-INF\lib下
将solrhome下 配置文件managed-schema 添加一个字段类型 使用ik分词器

<fieldType name="text_ik" class="solr.TextField" >  
      <analyzer type="index" isMaxWordLength="false" class="org.wltea.analyzer.lucene.IKAnalyzer"/>     
      <analyzer type="query" isMaxWordLength="true" class="org.wltea.analyzer.lucene.IKAnalyzer"/>   
    </fieldType> 

不能修改 StrField 不支持自定义分词器

<fieldType name="string" class="solr.StrField" sortMissingLast="true" >
</fieldType>

然后将对应需要进行中文分词的字段使用 text_ik该字段类型 比如

<dynamicField name="*_ik" type="text_ik" indexed="true"  stored="true"  multiValued="true"/>
重启 或者 cloud环境下重新生成collection 插入数据即可实现中文分词  通过某些中文关键字搜索

三.solr客户端

 solr提供的solrj java客户端可以使用java来添加和查询索引

使用maven引入solrj的依赖库

	<dependency>
  		<groupId>org.apache.solr</groupId>
  		<artifactId>solr-solrj</artifactId>
  		<version>5.5.4</version>
  	</dependency>
使用客户端操作添加和查询索引的代码
package cn.et;
import java.io.IOException;
import java.util.List;
import java.util.Map;

import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrQuery.ORDER;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.response.Group;
import org.apache.solr.client.solrj.response.GroupCommand;
import org.apache.solr.client.solrj.response.GroupResponse;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.GroupParams;


public class TestSolr {
	//获取solr的URL
	static String url="http://localhost:8080/solr/core1";
	static SolrClient solr;
	static{
		 solr= new HttpSolrClient(url);
	}
	public static void main(String[] args) throws Exception{
		group();
	}
	//删除,根据id删除
	public static void deleteById() throws Exception{
		UpdateResponse ur=solr.deleteById("2");
		solr.commit();
		solr.close();
	}
	//删除,根据内容删除
		public static void deleteByParam() throws Exception{
			UpdateResponse ur=solr.deleteByQuery("foodname_ik:鸡");
			solr.commit();
			solr.close();
		}
	//分组	
	public static void group() throws SolrServerException, IOException{	
		//查询的值
		SolrQuery solrquery=new SolrQuery("content_ik:桂林");
		//启用分组
		solrquery.setParam(GroupParams.GROUP, true);
		//按什么分组
		solrquery.setParam(GroupParams.GROUP_FIELD, "type_s");
		//是否获取统计的分组数量
		solrquery.setParam("group.ngroups", true);
		//显示每个分组显示的数量
		 //sq.setParam(GroupParams.GROUP_LIMIT, "5");  
		//默认只取分组中的第一条,需要设计
		solrquery.setParam(GroupParams.GROUP_LIMIT,"10");
		//获取到查询
		QueryResponse que= solr.query(solrquery);
		//获取分组的结果
		GroupResponse groupResponse = que.getGroupResponse();
		List<GroupCommand> values = groupResponse.getValues();
		//循环遍历
		for(GroupCommand groupCommand:values){
			//获取到所有分组
			List<Group> groups = groupCommand.getValues();
			for(Group group:groups){
				//获取到分组的组名
				System.out.println(group.getGroupValue());
				//获取到分组里面的所有成员
				SolrDocumentList result = group.getResult();
				for(SolrDocument doc:result){
					//获取到成员的名字
					System.out.println(doc.getFieldValue("content_ik"));
				}
				System.out.println("------------");
			}
			
		}
	}
	//查询
	public static void read() throws Exception{
		SolrQuery squery= new SolrQuery();
		//获取查询的值
		squery.setQuery("foodname_ik:鸡");
		//过滤查询不考虑得分,过滤不能高亮
		//squery.setFilterQueries("foodname_ik:鸡");
		//根据id倒叙排列
		squery.setSort("id", ORDER.asc);
		//分页查询两个参数
		//从第几个下标开始查询
		squery.setStart(0);
		//每次显示几个
		squery.setRows(2);
		//设计高亮
		//是否高亮
		squery.setHighlight(true);
		//高亮的词
		squery.set("foodname_ik");
		squery.set("hl.fl", "foodname_ik");
		//前缀
		squery.setHighlightSimplePre("<font color=red");
		//后缀
		squery.setHighlightSimplePost("</font>");
		//squery.set(HighlightParams.FIELDS, "foodname_ik");
		//查询
		QueryResponse qr=solr.query(squery);
		//获取最终的document
		SolrDocumentList results=qr.getResults();
		Map<String, Map<String, List<String>>> highlighting = qr.getHighlighting();
		//循环遍历出来
		for(SolrDocument doc:results){
			String id=doc.getFieldValue("id").toString();
			System.out.println(doc.getFieldValue("id"));
			System.out.println(doc.getFieldValue("foodname_ik"));
			Map<String, List<String>> map = highlighting.get(id);
			List<String> list = map.get("foodname_ik");
			String highStr=list.get(0);
			System.out.println(highStr);
		}
		solr.close();
	}
	//写入索引库
	public static void writer() throws Exception{
		
		SolrInputDocument document =new SolrInputDocument();
		document.addField("id", "5");
		document.addField("foodname_ik", "香酥鸡");
		//写入索引库
		UpdateResponse res= solr.add(document);
		solr.commit();
		solr.close();
	}
}

使用javabean的方式操作

javabean定义

package cn.et.test;

import org.apache.solr.client.solrj.beans.Field;

public class Food {
	 
	 public Food() {  
	 }  
	 
	 @Field  
	 private String id;  
	 @Field  
	 private String foodname_ik;   
	  
}

运行

package cn.et.test;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.FacetField.Count;
import org.apache.solr.client.solrj.response.PivotField;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.util.NamedList;
import org.junit.Test;

public class SolrTest {
	
	//获取solr的URL
	static String url="http://localhost:8080/solr/core1";
	//写入
	@Test  
    public void testWriteDoc() throws SolrServerException, IOException{  
        //连接solr
		HttpSolrClient solr=new HttpSolrClient(url);  
        //new实体类
        Food fd=new Food();
        fd.setId("15");  
        fd.setFoodname_ik("道口烧鸡");
        //写入
        solr.addBean(fd);  
        solr.commit();  
        solr.close();  
    }  
	//查询
	@Test  
    public void testReadDoc() throws SolrServerException, IOException{  
		//连接solr
		HttpSolrClient hsc=new HttpSolrClient(url);  
        SolrQuery sq=new SolrQuery();  
        //传入搜索的值
        sq.setQuery("foodname_ik:烧鸡");  
        //按什么排序
        sq.set("sort", "id asc");  
        //分页查询两个参数
      	//从第几个下标开始查询
        sq.setStart(0);  
    	//每次显示几个
        sq.setRows(1); 
      //获取最终的document
        List<Food> sdl=hsc.query(sq).getBeans(Food.class); 
        //循环遍历出来
        for(Food sd:sdl){  
            System.out.println(sd.getFoodname_ik());  
        }  
        hsc.close();  
    }  
	/**   
     * Facet 面 用于对搜索的结果进行分类    
     *  比如按国家分类   addFacetField 表示按某些字段进行分类是普通分类  结果为:   
     *   country_s   
            美国:6   
            中国:5   
        sq.addFacetQuery("age_i:[1 TO 20]");   
        sq.addFacetQuery("age_i:[21 TO 50]");   
        sq.addFacetQuery("age_i:[51 TO *]");   
        可以将多个范围值 添加到FacetQuery可以获取到这些Query的统计数量 比如   
         {age_i:[1 TO 20]=3, age_i:[20 TO 50]=5, age_i:[50 TO *]=5}    
        其他 参考 https://wiki.apache.org/solr/SimpleFacetParameters#facet.query_:_Arbitrary_Query_Faceting    
     */    
	@Test
	public void queryFacet() throws SolrServerException, IOException{
		//连接solr
		HttpSolrClient scs= new HttpSolrClient(url);
		SolrQuery sq= new SolrQuery();
		//启动facet
		sq.setFacet(true);
		//按字段分类 相同的归于同一类
		sq.addFacetField("country_s");
		//特殊分类 添加范围
		sq.addFacetQuery("age_i:[1 TO 20]");
		sq.addFacetQuery("age_i:[21 TO 50]");
		sq.addFacetQuery("age_i:[51 TO *]");
		//facet字段分类的前缀
		sq.setFacetPrefix("");
		//根据count数量 升序 和降序 也可以根据索引
		sq.setFacetSort("count asc");
		//获取查询的值
		sq.setQuery("*:*");
		//查询
		QueryResponse qr=scs.query(sq);
		//获取到查询的所有的facet
		List<FacetField> ff = qr.getFacetFields();
		//获取到范围分类的对应统计数量
		System.out.println(qr.getFacetQuery());
		//获取到根据字段分类的对应统计数量
		for(FacetField ft:ff){
			//按什么字段分类
			System.out.println(ft.getName());
			List<Count> cut = ft.getValues();
			for(Count count:cut){
				//类名和所属个数
				System.out.println(count.getName()+count.getCount());
			}
		}
		scs.commit();
		scs.close();
	}
	
	/**   
     * Facet  参考https://wiki.apache.org/solr/SimpleFacetParameters#Pivot_.28ie_Decision_Tree.29_Faceting   
     *  可以按照多维度来进行分类     
     *    比如按照国家分类后  再按照省份分类(国家和省份字段不要使用中文分词器 否则分类被拆成很多类别)   
     *       
     *  结果一般为:   
     *    美国6:   
     *      加利福尼亚州3     
     *      德克萨斯州3   
     *    中国5:   
     *      湖南省3   
     *      广东省2   
	 * @throws IOException 
	 * @throws SolrServerException 
   
     */    
	@Test
	public void queryF() throws SolrServerException, IOException{
		//连接solr
		HttpSolrClient scs= new HttpSolrClient(url);
		SolrQuery sq= new SolrQuery();
		//启动facet
		sq.setFacet(true);
		//按国家和省份进行二维分类 同一个字符串使用,隔开
		sq.addFacetPivotField("country_s,provice_s");
		//获取查询的值
		sq.setQuery("*:*");
		//查询
		QueryResponse qr=scs.query(sq,SolrRequest.METHOD.POST);
		//获取到查询的所有的facet
		NamedList<List<PivotField>> ff = qr.getFacetPivot();
		//遍历查询
		for(Map.Entry<String, List<PivotField>> me :ff){
			//获取最大的分类
			List<PivotField> lp = me.getValue();
			for(PivotField pf:lp){
				System.out.println("一级分类"+pf.getValue()+pf.getCount());
				//获取最大里分类的小分类
				List<PivotField> pit = pf.getPivot();
				for(PivotField pl:pit){
					System.out.println("二级分类"+pl.getValue()+pl.getCount());
				}
			}
		}
		scs.commit();
		scs.close();
		
	}
}



四.solr一些其他高级查询(参考代码)

package cn.et.solor;  
  
import java.io.IOException;  
import java.util.List;  
import java.util.Map;  
  
import org.apache.solr.client.solrj.SolrQuery;  
import org.apache.solr.client.solrj.SolrRequest;  
import org.apache.solr.client.solrj.SolrServerException;  
import org.apache.solr.client.solrj.impl.CloudSolrClient;  
import org.apache.solr.client.solrj.response.FacetField;  
import org.apache.solr.client.solrj.response.Group;  
import org.apache.solr.client.solrj.response.GroupCommand;  
import org.apache.solr.client.solrj.response.GroupResponse;  
import org.apache.solr.client.solrj.response.PivotField;  
import org.apache.solr.client.solrj.response.QueryResponse;  
import org.apache.solr.client.solrj.response.FacetField.Count;  
import org.apache.solr.common.params.GroupParams;  
import org.apache.solr.common.util.NamedList;  
import org.junit.Test;  
/**  
 * 支持一些高级特性 比如高亮 分类 分组 mtl(相似)  
{"id":"1","country_s":"美国","provice_s":"加利福尼亚州","city_s":"旧金山","age_i":"30","name_s":"John","desc_s":"John is come from austrina  John,s Dad is Johh Super"}  
{"id":"2","country_s":"美国","provice_s":"加利福尼亚州","city_s":"好莱坞","age_i":"40","name_s":"Mike","desc_s":"Mike is come from austrina  Mike,s Dad  is Mike Super"}  
{"id":"3","country_s":"美国","provice_s":"加利福尼亚州","city_s":"圣地牙哥","age_i":"50","name_s":"Cherry","desc_s":"Cherry is come from austrina  Cherry,s Dad  is Cherry Super"}  
{"id":"4","country_s":"美国","provice_s":"德克萨斯州","city_s":"休斯顿","age_i":"60","name_s":"Miya","desc_s":"Miya is come from austrina  Miya,s Dad  is Miya Super"}  
{"id":"5","country_s":"美国","provice_s":"德克萨斯州","city_s":"大学城","age_i":"70","name_s":"fubos","desc_s":"fubos is come from austrina  fubos,s Dad  is fubos Super"}  
{"id":"6","country_s":"美国","provice_s":"德克萨斯州","city_s":"麦亚伦","age_i":"20","name_s":"marry","desc_s":"marry is come from austrina  marry,s Dad  is marry Super"}  
{"id":"7","country_s":"中国","provice_s":"湖南省","city_s":"长沙市","age_i":"18","name_s":"张三","desc_s":"张三来自长沙市 是公务员一名"}  
{"id":"8","country_s":"中国","provice_s":"湖南省","city_s":"岳阳市","age_i":"15","name_s":"李四","desc_s":"李四来自岳阳市 是一名清洁工"}  
{"id":"9","country_s":"中国","provice_s":"湖南省","city_s":"株洲市","age_i":"33","name_s":"李光四","desc_s":"李光四 老家岳阳市 来自株洲 是李四的侄子"}  
{"id":"10","country_s":"中国","provice_s":"广东省","city_s":"深圳市","age_i":"67","name_s":"王五","desc_s":"王五来自深圳市  是来自深圳的一名海关缉私精英"}  
{"id":"11","country_s":"中国","provice_s":"广东省","city_s":"广州市","age_i":"89","name_s":"王冠宇","desc_s":"王冠宇是王五的儿子"}  
 */  
public class TestCloud {  
    /**  
     * 连接solrcloud  
     * @return  
     */  
    public CloudSolrClient getCloudSolrClient(){  
        String zkHost="localhost:2181";  
        CloudSolrClient csc=new CloudSolrClient(zkHost);  
        csc.setDefaultCollection("collection1");//集合名称  
        return csc;  
    }  
    /**  
     * solrcloud保存 修改 删除和单机相同  
     */  
    @Test  
    public void save() throws IOException, SolrServerException{  
        CloudSolrClient csc=getCloudSolrClient();  
        UserInfo ui=new UserInfo();  
        ui.setId("4");  
        ui.setName_s("王五");  
        ui.setAge_i(100);  
        csc.addBean(ui);  
        csc.commit();  
        csc.close();  
    }  
    /**  
     * solrcloud 删除  
     */  
    //@Test  
    public void delete() throws IOException, SolrServerException{  
        CloudSolrClient csc=getCloudSolrClient();  
        csc.deleteByQuery("*:*");  
        csc.commit();  
        csc.close();  
    }  
  
    /**  
     * solrcloud高亮显示  
     * 必须设置中文分词器  
     */  
    @Test  
    public void queryHign() throws IOException, SolrServerException{  
        CloudSolrClient csc=getCloudSolrClient();  
        SolrQuery sq=new SolrQuery();  
        sq.setQuery("desc_s:王五");  
        sq.addHighlightField("desc_s");  
        sq.setHighlight(true);  
        sq.setHighlightSimplePre("<font color=red>");  
        sq.setHighlightSimplePost("</font>");  
        QueryResponse qr=csc.query(sq);  
        List<UserInfo> userInfo=qr.getBeans(UserInfo.class);  
        Map<String, Map<String, List<String>>> highlighting = qr.getHighlighting();  
        System.out.println(highlighting);  
        for(UserInfo ui:userInfo){  
            System.out.println(ui.getName_s());  
        }  
        System.out.println(userInfo.size());  
        csc.commit();  
        csc.close();  
    }  
      
    /**  
     * Facet 面 用于对搜索的结果进行分类   
     *  比如按国家分类   addFacetField 表示按某些字段进行分类是普通分类  结果为:  
     *   country_s  
            美国:6  
            中国:5  
        sq.addFacetQuery("age_i:[1 TO 20]");  
        sq.addFacetQuery("age_i:[21 TO 50]");  
        sq.addFacetQuery("age_i:[51 TO *]");  
        可以将多个范围值 添加到FacetQuery可以获取到这些Query的统计数量 比如  
         {age_i:[1 TO 20]=3, age_i:[20 TO 50]=5, age_i:[50 TO *]=5}   
        其他 参考 https://wiki.apache.org/solr/SimpleFacetParameters#facet.query_:_Arbitrary_Query_Faceting   
     */  
    @Test  
    public void queryFacet() throws IOException, SolrServerException{  
        CloudSolrClient csc=getCloudSolrClient();  
        SolrQuery sq=new SolrQuery();  
          
        sq.setFacet(true);  
        //按字段分类 相同的归于一类  
        sq.addFacetField("country_s");  
        //特殊分类 添加范围  
        sq.addFacetQuery("age_i:[1 TO 20]");  
        sq.addFacetQuery("age_i:[21 TO 50]");  
        sq.addFacetQuery("age_i:[51 TO *]");  
        //这只facet字段分类的前缀  
        sq.setFacetPrefix("");  
        //根据 count 数量 升序和降序 也可以根据索引   
        sq.setFacetSort("count asc");  
        sq.setQuery("*:*");  
        QueryResponse qr=csc.query(sq);  
        List<FacetField> ff=qr.getFacetFields();  
        //获取到范围分类的对应统计数量  
        System.out.println(qr.getFacetQuery());  
        //获取到根据字段分类的对应统计数量  
        for(FacetField ftmp:ff){  
            System.out.println(ftmp.getName());  
            List<Count> cou=ftmp.getValues();  
            for (Count count : cou){  
                System.out.println(count.getName()+":"+ count.getCount());  
            }  
        }  
        csc.commit();  
        csc.close();  
    }  
      
    /**  
     * Facet  参考https://wiki.apache.org/solr/SimpleFacetParameters#Pivot_.28ie_Decision_Tree.29_Faceting  
     *  可以按照多维度来进行分类    
     *    比如按照国家分类后  再按照省份分类(国家和省份字段不要使用中文分词器 否则分类被拆成很多类别)  
     *      
     *  结果一般为:  
     *    美国6:  
     *      加利福尼亚州3    
     *      德克萨斯州3  
     *    中国5:  
     *      湖南省3  
     *      广东省2  
  
     */  
    @Test  
    public void queryFacetPivot() throws IOException, SolrServerException{  
        CloudSolrClient csc=getCloudSolrClient();  
        SolrQuery sq=new SolrQuery();  
        sq.setFacet(true);  
        //按国家和省份进行二维分类  同一个字符串使用,隔开  
        sq.addFacetPivotField("country_s,provice_s");  
        sq.setQuery("*:*");  
        QueryResponse qr=csc.query(sq,SolrRequest.METHOD.POST);  
        NamedList<List<PivotField>> ff=qr.getFacetPivot();  
        //获取到根据字段分类的对应统计数量  
        for(Map.Entry<String,List<PivotField>> me:ff){  
            List<PivotField> lpf=me.getValue();  
            for(PivotField pf:lpf){  
                System.out.println("一级分类:"+pf.getValue()+pf.getCount()+"---->");  
                List<PivotField> clpf=pf.getPivot();  
                for(PivotField cpf:clpf){  
                    System.out.println("二级分类:"+cpf.getValue()+cpf.getCount());  
                }  
            }  
        }  
        csc.commit();  
        csc.close();  
    }  
    /**  
     * 分组是分类的升级 同时可以获取到分组下的一部分元素(https://cwiki.apache.org/confluence/display/solr/Result+Grouping)  
       分组的字段的数据如果是集群环境 要求数据被写入到一个分片中 否则无法分组查询  
     */  
    @Test  
    public void queryGroup() throws IOException, SolrServerException{  
        CloudSolrClient csc=getCloudSolrClient();  
        SolrQuery sq=new SolrQuery();  
        //sq.setParam("shards.tolerant", true);  
        sq.setParam(GroupParams.GROUP,true);  
        sq.setParam(GroupParams.GROUP_FIELD, "country_s");  
        sq.setParam("group.ngroups", true);  
        //sq.setParam(GroupParams.GROUP_LIMIT, "5");  
        sq.setQuery("*:*");  
        sq.setRows(10);  
        QueryResponse qr=csc.query(sq);  
        GroupResponse ff=qr.getGroupResponse();  
          
        for(GroupCommand me:ff.getValues()){  
            System.out.println(me.getName());  
             List<Group> groups=me.getValues();  
             System.out.println(groups);  
              
        }  
        csc.commit();  
        csc.close();  
    }  
}  


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值