Group和Facet的概念很像,都是用来分组。Facet返回所有相关的结果并允许用户基于facet的目录重新定义结果集。Facet可以对分组数量进行过滤,以及排序,和日期范围,时间范围分组,但是如果你想得到具体的数据,还得需要查询一次或多次。group可以得到分组的组数量,一次请求,可以拿到所有的数据。
Group和Facet可以结合起来使用,但只能使用facet.field
和facet.range
,还不支持日期date和维度统计pivot faceting.
参数 | 类型 | 说明 |
---|---|---|
group | 布尔值 | 设为true,表示结果需要分组 |
group.field | 字符串 | 需要分组的字段,字段类型需要时是StrField或TextField |
group.func | 查询语句 | 可以指定查询函数 |
group.query | 查询语句 | 可以指定查询语句 |
rows | 整数 | 返回多少组结果,默认10 |
start | 整数 | 指定结果开始位置/偏移量 |
group.limit | 整数 | 每组返回多数条结果,默认1 |
group.offset | 整数 | 指定每组结果开始位置/偏移量 |
sort | 排序算法 | 控制各个组的返回顺序 |
group.sort | 排序算法 | 控制每一分组内部的顺序 |
group.format | grouped/simple | 设置为simple可以使得结果以单一列表形式返回 |
group.main | 布尔值 | 设为true时,结果将主要由第一个字段的分组命令决定 |
group.ngroups | 布尔值 | 设为true时,Solr将返回分组数量,默认fasle |
group.truncate | 布尔值 | 设为true时,facet数量将基于group分组中匹相关性高的文档,默认fasle |
group.cache.percent | 整数0-100 | 设为大于0时,表示缓存结果,默认为0。该项对于布尔查询,通配符查询,模糊查询有改善,却会减慢普通词查询。 |
public void SearchGroup(String QUERY_CONTENT,int QUERY_ROWS, Boolean GROUP, String GROUP_FIELD,String GROUP_LIMIT) {
SolrServer server = createSolrServer();
SolrQuery param = new SolrQuery();
param.setQuery("jobsName:"+QUERY_CONTENT);
param.setRows(QUERY_ROWS);
param.setParam(GroupParams.GROUP, GROUP);
param.setParam(GroupParams.GROUP_FIELD, GROUP_FIELD);
param.setParam(GroupParams.GROUP_LIMIT, GROUP_LIMIT);
QueryResponse response = null;
try {
response = server.query(param);
} catch (SolrServerException e) {
// logger.error(e.getMessage(), e);
}
Map info = new HashMap();
GroupResponse groupResponse = response.getGroupResponse();
if(groupResponse != null) {
List groupList = groupResponse.getValues();
for(GroupCommand groupCommand : groupList) {
List groups = groupCommand.getValues();
for(Group group : groups) {
info.put(group.getGroupValue(), (int)group.getResult().getNumFound());
System.out.println(group.getGroupValue()+"---"+group.getResult().getNumFound());
}
}
}
}
一、Group用法:
//组查询基础配置
params.set(GroupParams.GROUP, "true");
params.set(GroupParams.GROUP_FIELD, "dkeys");根据dkeys域上的值来分组划分结果,建议dkeys上不要分词;
params.set(GroupParams.GROUP_LIMIT, "5");
params.set(GroupParams.GROUP_FORMAT, "grouped");
params.set(GroupParams.GROUP_MAIN, "false");
Group查询结果遍历方式:
QueryResponse response = solrServer.query(query);
GroupResponse groupResponse = response.getGroupResponse();
List ls = groupResponse.getValues();
for(GroupCommand gc:ls){
List list = gc.getValues();
for(Group g : list){
SolrDocumentList sdl = g.getResult();
if (CollectionUtils.isNotEmpty(sdl)) {
for (SolrDocument doc : sdl) {
System.out.println(doc.toString());//相同的dkeys下的文档每5个作为一组返回;
}
}
}
}
此时普通遍历结果的方法无效:
SolrDocumentList results = response.getResults();
System.out.println(ls+"\t\t"+results);//输出null
参数 | 描述 |
facet | 为TRUEON时,启用该功能 |
facet.query | 默认情况下,Solr会自动Facet的field并返回其相关的计数结果 。指定Lucene语法的查询语句,可以覆盖默认行为。可以设置多个 日期区间查询: facet.query=date:[2009-1-1T0:0:0Z TO 2009-2-1T0:0:0Z] 数字区间统计; facet.query=price:[5000 TO 10000] |
facet.field | 指定作为facet的field。比如“品牌”,可以设置多个 |
facet.prefix | 以此值为前辍的terms才会作为Facet |
facet.contains | 字符串包含此值的terms才会作为Facet |
facet.contains.ignoreCase | 匹配 facet.contains 条件时,忽略大小写 |
facet.sort | 指示Facet结果如何排序。有两个值:1. count -- facet记录数多的排前面 2. index -- 按索引中的次序 |
facet.limit | 限制返回的facet的数量。默认100. 为负数时表示不做限制。e.g. 设置为2的话,只返回品牌、类型和颜色中的2种。 |
facet.offset | 默认0. 一般用于分页时,忽略前面多少个 |
facet.minCount | 设置最小的数量。限制了Facet字段值的最小count,默认为0.合理设置该参数可以将用户的关注点集中在少数比较热门的领域.相当于group by having |
facet.missing | 默认值false. 如果设置为true或者on,那么将统计那些该Facet字段值为null的记录 |
facet.method | facet的算法。三个可选值:enum, fc(默认值),fcs;enum适用于字段值比较少的情况,比如字段类型为布尔型,或者字段表示中国的所有省份 |
facet.exists | 用于facet.method=enum的情况 |
facet.excludeTerms | 排除某些terms |
facet.threads | 获得facet的计算的线程数 |
facet.date | 该参数表示需要进行Date Facet的字段名,与facet.field一样,该参数可以被设置多次,表示对多个字段进行Date Facet |
facet.date.start | 起始时间 |
facet.date.end | 结束时间 |
facet.date.gap | 时间间隔.如果start为2009-1-1,end为2010-1-1.gap设置为+1MONTH表示间隔1个月,那么将会把这段时间划分为12个间隔段。注意+因为是特殊字符所以应该用%2B代替 |
facet.date.hardend | 取值可以为true|false,默认为false.它表示gap迭代到end处采用何种处理.举例说明start为2009-1-1,end为2009-12-25,gap为+1MONTH; hardend为false的话最后一个时间段为2009-12-1至2010-1-1; hardend为true的话最后一个时间段为2009-12-1至2009-12-25 |
facet.date.other | 取值范围为before|after|between|none|all,默认为none,before会对start之前的值做统计,after会对end之后的值做统计,between会对start至end之间所有值做统计.如果hardend为true的话,那么该值就是各个时间段统计值的和.none表示该项禁用.all表示before,after,all都会统计 |
facet.range | 范围统计分组统计,跟Date Facet一样,只是他们定位的字段的类型不同,Data Fact是做日期的分组统计的,而Fact Range是做数字分组统计的,在次强调,是做数字分组统计的,对于字符串,日期是不可以的 |
facet.range.start |
|
facet.range.end | |
facet.range.gap | |
facet.range.hardend | |
facet.range.other | |
facet.range.include |
public JiucaiyunSolrResponseDTO queryData(JiucaiyunSolrRequestDTO request) throws JiucaiyunSolrException {
try {
// int index = 5/0;
// 索引条件
SolrQuery params = new SolrQuery();
params.setQuery(request.getkeywords());
String keyWord = "*";
if (request.getkeywords() != null && !"".equals(request.getkeywords().trim())) {
keyWord = request.getkeywords().trim();
}
params.set("q", "keywords:" + keyWord);
if (null != request.getcatalog() && !"".equals(request.getcatalog().trim())) {
params.add("fq", "catalog:" + request.getcatalog().trim());
}
String brand2 = request.getbrand();
if (null != brand2 && !"".equals(brand2.trim())) {
if (brand2.contains(" ")) {
brand2 = brand2.trim().replace(" ", "\\ ");
}
// brand2 = SolrUtils.transformSolrMetacharactor(brand2);
params.add("fq", "brand:" + brand2);
}
if (null != request.getprice()) {
String[] price = request.getprice().split("-");
if (price.length == 2) {
params.add("fq", "price:[" + price[0] + " TO " + price[1] + "]");
} else {
params.add("fq", "price:[" + price[0] + " TO *]");
}
}
String model2 = request.getmodel();
if (null != model2 && !"".equals(model2.trim())) {
if (model2.contains(" ")) {
model2 = model2.trim().replace(" ", "\\ ");
}
// brand2 = SolrUtils.transformSolrMetacharactor(brand2);
params.add("fq", "model:" + model2);
}
if (null != request.gettype() && !"".equals(request.gettype().trim())) {
params.add("fq", "type:" + request.gettype().trim());
}
if (null != request.getsupplierid() && !"".equals(request.getsupplierid().trim())) {
String[] strs = request.getsupplierid().split(",");
if (strs.length > 1) {
String per = "";
for (int i = 0; i < strs.length; i++) {
if (i == 0) {
per = per + " supplierid:" + strs[i];
} else {
per = per + " OR supplierid:" + strs[i];
}
}
params.add("fq", per);
} else {
params.add("fq", "supplierid:" + request.getsupplierid().trim());
}
}
if (null != request.getsuppliernum() && !"".equals(request.getsuppliernum().trim())) {
params.add("fq", "suppliernum:" + request.getsuppliernum().trim());
}
if (null != request.getpermission() && !"".equals(request.getpermission().trim())) {
String[] pers = request.getpermission().trim().split(",");
String per = "permission:\"\"";
for (String str : pers) {
per = per + " OR permission:" + str;
}
params.add("fq", per);
}
// 1:打开高亮的开关
if (null != request.getkeywords() && !"".equals(request.getkeywords().trim())) {
params.setHighlight(true);
// 2:设置需要高亮的域
params.addHighlightField("supplier_name");
params.addHighlightField("name");
// 3:高亮的前缀 后缀
params.setHighlightSimplePre("");
params.setHighlightSimplePost("");
}
// 分页
params.setStart(request.getStartRow());
params.setRows(request.getPageSize());
// 排序
if ("asc".equals(request.getprice_order()) && (null == request.getsalesvolume_order()
|| "".equals(request.getsalesvolume_order().trim()))) {
params.setSort("price", ORDER.asc);
} else if ("desc".equals(request.getprice_order())
&& (null == request.getsalesvolume_order()
|| "".equals(request.getsalesvolume_order().trim()))) {
params.setSort("price", ORDER.desc);
}
if (null != request.getsalesvolume_order() && (null == request.getprice_order()
|| "".equals(request.getprice_order().trim()))) {
params.setSort("salesvolume", ORDER.desc);
}
params.set("wt", "json");
params.set("facet", true);
params.add("facet.field", "catalog_name");
params.add("facet.field", "brand");
params.add("facet.field", "model");
params.add("facet.field", "type");
QueryResponse query = solrClient.query(params);
List facetFields = query.getFacetFields();
List category = new ArrayList();
List brands = new ArrayList();
List type = new ArrayList();
List models = new ArrayList();
for (FacetField ff : facetFields) {
String name = ff.getName();
switch (name) {
case "catalog_name":
List cate = ff.getValues();
for (Count c : cate) {
if (c.getCount() > 0) {
String[] strs = c.getName().split(",");
category.add(new JiucaiyunSolrCategoryDTO(strs[0], strs[1]));
}
}
break;
case "brand":
List brand = ff.getValues();
for (Count c : brand) {
if (c.getCount() > 0) {
brands.add(new JiucaiyunSolrBrandDTO(c.getName()));
}
}
break;
case "type":
List t = ff.getValues();
for (Count c : t) {
if (c.getCount() > 0) {
type.add(new JiucaiyunSolrTypeDTO(c.getName()));
}
}
break;
case "model":
List model = ff.getValues();
for (Count c : model) {
if (c.getCount() > 0) {
models.add(new JiucaiyunSolrModelDTO(c.getName()));
}
}
break;
default:
break;
}
}
SolrDocumentList results = query.getResults();
// 获取高亮
Map>> highlighting = query.getHighlighting();
// 1: Map K id V : map
// 2: Map K name_ik V list
// 3: list apache 不一个 多值 本次只有一个值 list.get(0)
// 总条数
long numFound = results.getNumFound();
List goodsList = new ArrayList();
for (SolrDocument doc : results) {
JiucaiyunSolrProductDTO product = new JiucaiyunSolrProductDTO();
// 商品ID
String id = (String) doc.get("id");
product.setId(id);
Map> map = new HashMap>();
if (null != highlighting) {
map = highlighting.get(id);
}
// 商品名称
if (null != map && null != map.get("name")) {
product.setName(map.get("name").get(0));
} else {
product.setName((String) doc.get("name"));
}
product.setName1((String) doc.get("name"));
// 供应商名称
if (null != map && null != map.get("supplier_name")) {
product.setSupplier(map.get("supplier_name").get(0));
} else {
product.setSupplier((String) doc.get("supplier_name"));
}
product.setSupplier1((String) doc.get("supplier_name"));
// 供应商编码
product.setSuppliernum((String) doc.get("suppliernum"));
// 供应商id
product.setSupplierid((String) doc.get("supplierid"));
// wareId
product.setWareid((String) doc.get("wareid"));
// 商品sku
product.setGoodsnum((String) doc.get("num"));
// 商品品牌
product.setBrand((String) doc.get("brand"));
// 规格
product.setModel((String) doc.get("model"));
// 商品url
product.setUrl((String) doc.get("picture"));
// 商品imgid
product.setImgid((String) doc.get("pictureid"));
// 商品价格
product.setPrice(String.valueOf(doc.get("price")));
// 商品有效期
product.setSuccessdate((String) doc.get("successdate"));
// 商品销量
product.setSalesvolume((String) doc.get("salesvolume"));
// 起购量
product.setMinimumquantity((String) doc.get("minimum_quantity"));
if (null != request.getlevel() && !"".equals(request.getlevel())) {
Integer goodsid = null;
if (this.isNumeric(product.getId())) {
goodsid = Integer.valueOf(product.getId());
BigDecimal levelPrice = jiucaiyunSolrDao.getLevelPrice(goodsid, request.getlevel());
if (null != levelPrice) {
product.setPrice(levelPrice + "");
}
}
}
goodsList.add(product);
}
JiucaiyunSolrResponseDTO response = new JiucaiyunSolrResponseDTO();
response.setGoodsList(goodsList);
response.setBrands(brands);
response.setCategory(category);
response.setType(type);
response.setModels(models);
response.setTotalnum(numFound);
if (null != request.getsupplierid() && !"".equals(request.getsupplierid().trim())) {
String[] strs = request.getsupplierid().split(",");
List suppliers = new ArrayList<>();
for (String str : strs) {
int supplierid = Integer.parseInt(str);
JiucaiyunSolrSupplierDTO supplier = querySupplier(supplierid);
suppliers.add(supplier);
}
response.setSuppliers(suppliers);
response.setSupplier(suppliers.get(0));
}
return response;
} catch (Exception e) {
// logger.error(e.getMessage(),e);
e.printStackTrace();
return null;
}
}