搜索引擎solr
企业级搜索solr应用
一 。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
直接访问 出现404 找到tomcat/logs/localhost.2017-08-17.log 日志 出现以下异常
- java.lang.NoClassDefFoundError: Failed to initialize Apache Solr: Could not find necessary SLF4j logging jars.
- If using Jetty, the SLF4j logging jars need to go in the jetty lib/ext directory. For other containers,
- the corresponding directory should be used. For more information, see: http://wiki.apache.org/solr/SolrLogging
- at org.apache.solr.servlet.CheckLoggingConfiguration.check(CheckLoggingConfiguration.java:27)
- at org.apache.solr.servlet.BaseSolrFilter.<clinit>(BaseSolrFilter.java:30)
可用看到缺少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)
- 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)
3》配置solrhome
找到 tomcat\solr\WEB-INF\web.xml 编辑 找到以下这段(配置solrhome) 去掉注释 将第二个参数配置为本地任意一个目录即可
- <env-entry>
- <env-entry-name>solr/home</env-entry-name>
- <env-entry-value>D:\learn\solr-5.5.4\home</env-entry-value>
- <env-entry-type>java.lang.String</env-entry-type>
- </env-entry>
http://localhost:8080/solor/index.html 或者 http://localhost:8080/solr/admin.html
4》配置core(core类似于数据库可以插入多个document(数据库表行)每个document拥有多个 field 数据库的列)
solrhome下新建一个core目录 比如mycore
拷贝 solr解压包下\server\solr\configsets\basic_configs到新建目录 mycore中
进入solr管理网页 点击 core admin 添加该core
点击Add core后 成功后 检查 mycore目录 发现多了 core.properties和data两个资源
登陆solr管理网站发现 列表中多了mycore
4》配置文件理解
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" />
- 表示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拷贝mycore为mycore1 管理平台添加core 设置参数为 路径,路径来设置需要搜索的核
- String shards = "localhost:8080/solr/mycore,localhost:8080/solr/mycore1";
- 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>
代码修改对应的方法即可
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);
- }
- }
- /**
- *
- */
- 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);
- }
- }
将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>
<fieldType name="string" class="solr.StrField" sortMissingLast="true" >
</fieldType>
然后将对应需要进行中文分词的字段使用 text_ik该字段类型 比如
- <dynamicField name="*_s" type="text_ik" indexed="true" stored="true" />
三。solr客户端
solr提供的solrj java客户端可以使用java来添加和查询索引
使用maven引入solrj的依赖库
- <!-- https://mvnrepository.com/artifact/org.apache.solr/solr-solrj -->
- <dependency>
- <groupId>org.apache.solr</groupId>
- <artifactId>solr-solrj</artifactId>
- <version>5.5.3</version>
- </dependency>
- public class TestCrud {
- //请求的url
- public static final String url="http://localhost:8080/solr/mycore";
- /**
- * 测试写入数据到solr
- * @throws IOException
- * @throws SolrServerException
- */
- @Test
- public void testWriteDoc() throws SolrServerException, IOException{
- HttpSolrClient hsc=new HttpSolrClient(url);
- SolrInputDocument sid=new SolrInputDocument();
- sid.addField("id", 1);
- sid.addField("name_s","张三");
- hsc.add(sid);
- hsc.commit();
- hsc.close();
- }
- /**
- * 测试从solr读取数据
- * @throws IOException
- * @throws SolrServerException
- */
- @Test
- public void testReadDoc() throws SolrServerException, IOException{
- HttpSolrClient hsc=new HttpSolrClient(url);
- SolrQuery sq=new SolrQuery();
- sq.setQuery("name_s:*");
- sq.set("sort", "id asc");
- sq.setStart(0);
- sq.setRows(1);
- SolrDocumentList sdl=hsc.query(sq).getResults();
- for(SolrDocument sd:sdl){
- System.out.println(sd.getFieldValue("name_s"));
- }
- hsc.close();
- }
- /**
- * 测试通过id删除
- * @throws IOException
- * @throws SolrServerException
- */
- @Test
- public void testDelDoc() throws SolrServerException, IOException{
- HttpSolrClient hsc=new HttpSolrClient(url);
- hsc.deleteById("1");
- hsc.commit();
- hsc.close();
- }
- }
使用javabean的方式操作
javabean定义
- import org.apache.solr.client.solrj.beans.Field;
- public class UserInfo {
- public UserInfo() {
- }
- @Field
- private String id;
- @Field
- private String name_s;
- @Field
- private int age_i;
- }
- /**
- * 测试写入数据到solr
- * @throws IOException
- * @throws SolrServerException
- */
- @Test
- public void testWriteDoc() throws SolrServerException, IOException{
- HttpSolrClient hsc=new HttpSolrClient(url);
- UserInfo ui=new UserInfo();
- ui.setId("2");
- ui.setName_s("李四");
- ui.setAge_i(100);
- hsc.addBean(ui);
- hsc.commit();
- hsc.close();
- }
- /**
- * 测试从solr读取数据
- * @throws IOException
- * @throws SolrServerException
- */
- @Test
- public void testReadDoc() throws SolrServerException, IOException{
- HttpSolrClient hsc=new HttpSolrClient(url);
- SolrQuery sq=new SolrQuery();
- sq.setQuery("name_s:*");
- sq.set("sort", "id asc");
- sq.setStart(0);
- sq.setRows(1);
- List<UserInfo> sdl=hsc.query(sq).getBeans(UserInfo.class);
- for(UserInfo sd:sdl){
- System.out.println(sd.getName_s());
- }
- hsc.close();
- }
四。solr集群安装
1》集群方式:
solr集群目前有两种方式 主从模式和solrcloud模式(推荐方式)
solrcloud通过zookeeper管理集群 通过将索引切片的方式分发到不同的后端服务器中 后端服务器 可以通过一主多从的方式来实现高可用 一主多从
通过leader的管理方式 leader负责写入 从机负责分摊并发读取 leader挂掉后 从机选举出新的leader继续进行管理
2》solrcloud集群概念
solrcloud分为逻辑层和物理层
逻辑层:
》Cluster(表示zookeeper集群) 用于管理solrcloud的实例collection
》Collection 表示一个solrcloud的实例 能够被切分为多个片
》Shards (片) 一个Collection 可以被切分为多个片 片的个数决定了并发量的大小 每个片拥有多个备份 其中包括leader 负责写入 replica负责容灾和读请求
物理层:
》 Cluster由多个solr 节点(物理机器)组成 每个节点对应linux的后台进程
》 Node(节点) 每个节点由多个Core组成
》 Core 每个片在该节点的拷贝都属于一个core 可能每个片都有一份拷贝在当前机器上 当前机器 可能有多个core
》Replica 是每个切片的一份拷贝 必须使用使用相同的配置 该配置需要写入到zookeeper中
3》solrcloud集群实现(伪集群)
》》拷贝三份tomcat 分别修改server.xml tomcat端口 (8080,8081,8082)
》》同单机安装拷贝solr应用到webapps目录下 修改web.xml 分别指向不同的solrhome
比如我的配置
tomcat1 | 8080 | D:\learn\solr-5.5.4\home |
tomcat2 | 8081 | D:\learn\solr-5.5.4\home1 |
tomcat3 | 8082 | D:\learn\solr-5.5.4\home2 |
》》拷贝 solr解压包下\server\solr到新建目录D:\learn\solr-5.5.4\home中 同时拷贝到hom1和home2
solr解压包下\server\solr\configsets\basic_configs到新建目录D:\learn\solr-5.5.4\home(只拷贝home 不拷贝home1和home2) 改名为
collections1
》》tomcat/bin下的 catalina.cmd添加
tomcat1下设置为:
- set JAVA_OPTS=-Dsolr.solr.home=D:/learn/solr-5.5.4/home -Dbootstrap_confdir=D:/learn/solr-5.5.4/home/collection1/conf
- -Dcollection.configName=myconf -DnumShards=3 -DzkHost=localhost:2181
- set JAVA_OPTS=-Dsolr.solr.home=D:/learn/solr-5.5.4/home -DzkHost=localhost:2181
依次启动 zookeeper 和所有的tomcat 访问 http://localhost:8080/solr/admin.html
》》使用命令创建collection (其他操作参考 https://cwiki.apache.org/confluence/display/solr/Collections+API)
- http://localhost:8081/solr/admin/collections?action=CREATE&name=collection1&numShards=3&replicationFactor=3&maxShardsPerNode=3&collection.configName=myconf
》》查看zookeeper信息和集群分片信息
查看zookeeper中写入的数据
查看分片到哪些节点
五。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();
- }
- }