solr4.7开发实践 3——分组查询facet

2019-03-27 01:21|来源: 网路

solr将以导航为目的的查询结果称为facet. 它并不会修改查询结果信息, 只是在查询结果上根据分类添加了count信息, 然后用户根据count信息做进一步的查询, 比如淘宝的查询列表中, 上面会表示不同的类目相关查询结果的数量. 

比如搜索数码相机, 在搜索结果栏会根据厂商, 分辨率等维度列出, 这里厂商, 分辨率就是一个个facet. 

然后在厂商下面会有nikon, canon, sony等品牌, 这个叫约束(constraints) 

接下来是根据选择, 列出当前的导航路径, 这个叫面包屑(breadcrumb). 

solr有几种facet: 
普通facet, 比如从厂商品牌的维度建立fact 
查询facet, 比如根据价格查询时, 将根据价格, 设置多个区间, 比如0-10, 10-20, 20-30等 
日期facet, 也是一种特殊的范围查询, 比如按照月份进行facet. 

facet的主要好处就是可以任意对搜索条件进行组合, 避免无效搜索, 改善搜索体验. 

facet都是在查询时通过参数指定. 比如 
在http api中这样写: 

引用

"&facet=true&facet.field=manu"

java代码 solrj这样写: 

   query.setFacet(true);//是否分组查询
   query.setRows(0);//设置返回结果条数,如果你时分组查询,你就设置为0
   query.addFacetField("region");//增加分组字段   q
   query.addFacetField("theme");//增加分组字段   q
   QueryResponse rsp = server.query(query);
   //取出结果  
   FacetField facetField = rsp.getFacetField("region");
   List<Count> counts = null;
   if (facetField != null) {
     counts = facetField.getValues();
     if (counts != null) {
      for (Count count : counts) {
       if (count.getCount() != 0) {
        listRegion.add(count.getName()+"("+count.getCount()+")");
      }
      }
      map.put("region", listRegion);
     }
   }
   
   FacetField facetFieldTheme = rsp.getFacetField("theme");
   List<Count> countsTheme = null;
   if (facetFieldTheme != null) {
    countsTheme = facetFieldTheme.getValues();
     if (countsTheme != null) {
      for (Count count : countsTheme) {
         if (count.getCount() != 0) {
        listTheme.add(count.getName()+"("+count.getCount()+")");
      }
      }
      map.put("theme", listTheme);
     }
   }

而xml返回的结果为这样: 

<lst name="facet_fields">
            <lst name="manu">
               <int name="Canon USA">17</int>
               <int name="Olympus">12</int>
               <int name="Sony">12</int>
               <int name="Panasonic">9</int>
               <int name="Nikon">4</int>
            </lst>
</lst>

通过java代码可以这样获取facet结果:

List<FacetField> facetFields = queryResponse.getFacetFields();

在已有的查询基础上增加facet query, 可以这样写: 

solrQuery.addFacetQuery("quality:[* TO 10]")

比如对价格按照指定的区间进行facet, 可以这样加上facet后缀: 

引用

&facet=true&facet.query=price:[* TO 100] 
&facet.query=price:[100 TO 200];&facet.query=[price:200 TO 300] 
&facet.query=price:[300 TO 400];&facet.query=[price:400 TO 500] 
&facet.query=price:[500 TO *]



如果要对价格在400到500期间的产品做进一步的搜索, 那么可以这样写(使用了solr的过滤查询): 

引用

http://localhost:8983/solr/select?q=camera &facet=on&facet.field=manu&facet.field=camera_type &fq=price:[400 to 500]



注意这里的facet field不再包含price了 

如果这里对类型做进一步的查询, 那么query语句可以这样写: 

引用

http://localhost:8983/solr/select?q=camera &facet=on&facet.field=manu &fq=price:[400 to 500] &fq=camera_type:SLR 



facet的使用场景: 
1.类目导航 
2.自动提示, 需要借助一个支持多值的tag field. 
3.热门关键词排行, 也需要借助一个tag field 

 


转自:http://my.oschina.net/MrMichael/blog/222746

相关问答

更多
  • public static Map<String, Integer> queryByGroup(String qStr,String groupField,String sortField,boolean asc,Integer pageSize,Integer pageNum){ Map<String, Integer> rmap = new LinkedHashMap<String, Integer>(); try { SolrServer server = getS ...
  • Facet Query上的通配符卡应该可以工作 。 由于通配符查询不进行任何分析,您可以尝试fq=MyField:valx* 你在尝试的不是过滤而是搜索。 使用带有小q=MyField:valx滤器的空格标记器并搜索q=MyField:valx ,它将匹配结果。 您也可以使用前缀和通配符查询。 Wildcard card on Facet Query should work. As wildcard queries does not undergo any analysis, you can try fq= ...
  • 经过一些研发后发现,solr有提供自定义间隔的条款。 这可以通过它来实现。 Found this after some r&d, solr has a clause for providing custom intervals. This can be achieved through it.
  • 如果您要进行查询 - 请执行查询。 Lucene针对查询进行了高度优化,因此您应该这样做。 facet查询用于从任意查询创建构面(计数) - 因此在内部它执行相同的操作。 如果你生成一个facet然后遍历那个facet,那么Lucene必须查看的文档比你查询单个值时要多得多。 获得性能提升的最佳策略是批量执行这些操作 - 检查同一批次中的500本书(即isbn:(123 OR 321 OR 567 OR 765) ),然后在代码中处理。 如果这些更新可以并行地从许多系统到达,而不需要通过单一来源,那么您必须 ...
  • 改变facet.method可能有所帮助。 fc作为默认值不适用于全文字段的分面。 在我的情况下, enum帮助: http://localhost:8983/solr/collection1/autocomplete_en?facet.prefix=sol&facet.method=enum... 但对于较大的索引,即使enum也可能太慢。 如果您不需要查询过滤器,则应考虑建议组件: http : //wiki.apache.org/solr/Suggester 近实时也是一个问题。 但在大多数用例中, ...
  • 将text_path字段定义更改为仅在索引时间应用PathHierarchyTokenizerFactory(以下示例)。 你的问题是你的查询是由标记器处理的,所以fq = libraries:“/ test / subtest”实际上是针对fq =库进行查询的:(/ test / subtest OR / test)。
  • 对于过滤器查询,如果未指定该字段,则查询将在默认字段上起作用。 您可以通过添加debugQuery=on来检查执行的过滤器查询 text:solr100 因此,检查默认字段是否应具有CABERNET术语。 此外,匹配将取决于字段类型,执行的分析以及字段索引与否的位置。 只有索引的字段才能过滤结果。 For the filter queries if the field is not speci ...
  • 如果我理解正确你想要'每个标签的唯一内容数',对吗? 如果是这样, json facets会这样做: curl http://.../query -d 'q=*:*&json.facet={ tags:{terms:{ field : Tag, facet:{ "unique" : "unique(Content)" } }} }' if I understand correctly you want 'count of unique Cont ...
  • 我自己找到了答案。 我应该使用More Like This处理程序,而不是使用搜索处理程序的MLT。 MLT处理程序“支持使用CommonQueryParameters进行分面,分页和过滤”(来自wiki)。 启用MLT功能的两种方法http://wiki.apache.org/solr/MoreLikeThis 更像是这个处理程序http://wiki.apache.org/solr/MoreLikeThisHandler#Examples Found the answer myself. I am su ...
  • 我认为这不可能在solr结束。 但是你需要在客户端实现同样的目标。 当你得到json响应时,你可以通过添加'+'来修改它。 要么 您在UI前面显示构面计数的位置,您只需在显示计数之前添加“+”作为前缀。 I don't think so this possible at solr end. But you need to achieve the same thing at client side. When you get json response you modify the same by addin ...