solr的facet解读
开发采用更加灵活的solr搜索服务器来实现分层功能。
1.QueryResponse类:
view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
public class QueryResponse extends SolrResponseBase
{
// Direct pointers to known types
private NamedList<Object> _header = null;
private SolrDocumentList _results = null;
private NamedList<ArrayList> _sortvalues = null;
private NamedList<Object> _facetInfo = null;
private NamedList<Object> _debugInfo = null;
private NamedList<Object> _highlightingInfo = null;
private NamedList<Object> _spellInfo = null;
// Facet stuff
private Map<String,Integer> _facetQuery = null;
private List<FacetField> _facetFields = null;
private List<FacetField> _limitingFacets = null;
private List<FacetField> _facetDates = null;
// Highlight Info
private Map<String,Map<String,List<String>>> _highlighting = null;
// SpellCheck Response
private SpellCheckResponse _spellResponse = null;
// Debug Info
private Map<String,Object> _debugMap = null;
private Map<String,String> _explainMap = null;
// utility variable used for automatic binding -- it should not be serialized
private transient final SolrServer solrServer;
//.....
//.....
private void extractFacetInfo( NamedList<Object> info )
{
// Parse the queries
_facetQuery = new HashMap<String, Integer>();
NamedList<Integer> fq = (NamedList<Integer>) info.get( "facet_queries" );
for( Map.Entry<String, Integer> entry : fq ) {
_facetQuery.put( entry.getKey(), entry.getValue() );
}
// Parse the facet info into fields
// TODO?? The list could be <int> or <long>? If always <long> then we can switch to <Long>
NamedList<NamedList<Number>> ff = (NamedList<NamedList<Number>>) info.get( "facet_fields" );
if( ff != null ) {
_facetFields = new ArrayList<FacetField>( ff.size() );
_limitingFacets = new ArrayList<FacetField>( ff.size() );
long minsize = _results.getNumFound();
for( Map.Entry<String,NamedList<Number>> facet : ff ) {
FacetField f = new FacetField( facet.getKey() );
for( Map.Entry<String, Number> entry : facet.getValue() ) {
f.add( entry.getKey(), entry.getValue().longValue() );
}
_facetFields.add( f );
FacetField nl = f.getLimitingFields( minsize );
if( nl.getValueCount() > 0 ) {
_limitingFacets.add( nl );
}
}
}
//Parse date facets
NamedList<NamedList<Object>> df = (NamedList<NamedList<Object>>) info.get("facet_dates");
if (df != null) {
// System.out.println(df);
_facetDates = new ArrayList<FacetField>( df.size() );
for (Map.Entry<String, NamedList<Object>> facet : df) {
// System.out.println("Key: " + facet.getKey() + " Value: " + facet.getValue());
NamedList<Object> values = facet.getValue();
String gap = (String) values.get("gap");
Date end = (Date) values.get("end");
FacetField f = new FacetField(facet.getKey(), gap, end);
for (Map.Entry<String, Object> entry : values) {
try {
f.add(entry.getKey(), Long.parseLong(entry.getValue().toString()));
} catch (NumberFormatException e) {
//Ignore for non-number responses which are already handled above
}
}
_facetDates.add(f);
}
}
}
}
public class QueryResponse extends SolrResponseBase
{
// Direct pointers to known types
private NamedList<Object> _header = null;
private SolrDocumentList _results = null;
private NamedList<ArrayList> _sortvalues = null;
private NamedList<Object> _facetInfo = null;
private NamedList<Object> _debugInfo = null;
private NamedList<Object> _highlightingInfo = null;
private NamedList<Object> _spellInfo = null;
// Facet stuff
private Map<String,Integer> _facetQuery = null;
private List<FacetField> _facetFields = null;
private List<FacetField> _limitingFacets = null;
private List<FacetField> _facetDates = null;
// Highlight Info
private Map<String,Map<String,List<String>>> _highlighting = null;
// SpellCheck Response
private SpellCheckResponse _spellResponse = null;
// Debug Info
private Map<String,Object> _debugMap = null;
private Map<String,String> _explainMap = null;
// utility variable used for automatic binding -- it should not be serialized
private transient final SolrServer solrServer;
//.....
//.....
private void extractFacetInfo( NamedList<Object> info )
{
// Parse the queries
_facetQuery = new HashMap<String, Integer>();
NamedList<Integer> fq = (NamedList<Integer>) info.get( "facet_queries" );
for( Map.Entry<String, Integer> entry : fq ) {
_facetQuery.put( entry.getKey(), entry.getValue() );
}
// Parse the facet info into fields
// TODO?? The list could be <int> or <long>? If always <long> then we can switch to <Long>
NamedList<NamedList<Number>> ff = (NamedList<NamedList<Number>>) info.get( "facet_fields" );
if( ff != null ) {
_facetFields = new ArrayList<FacetField>( ff.size() );
_limitingFacets = new ArrayList<FacetField>( ff.size() );
long minsize = _results.getNumFound();
for( Map.Entry<String,NamedList<Number>> facet : ff ) {
FacetField f = new FacetField( facet.getKey() );
for( Map.Entry<String, Number> entry : facet.getValue() ) {
f.add( entry.getKey(), entry.getValue().longValue() );
}
_facetFields.add( f );
FacetField nl = f.getLimitingFields( minsize );
if( nl.getValueCount() > 0 ) {
_limitingFacets.add( nl );
}
}
}
//Parse date facets
NamedList<NamedList<Object>> df = (NamedList<NamedList<Object>>) info.get("facet_dates");
if (df != null) {
// System.out.println(df);
_facetDates = new ArrayList<FacetField>( df.size() );
for (Map.Entry<String, NamedList<Object>> facet : df) {
// System.out.println("Key: " + facet.getKey() + " Value: " + facet.getValue());
NamedList<Object> values = facet.getValue();
String gap = (String) values.get("gap");
Date end = (Date) values.get("end");
FacetField f = new FacetField(facet.getKey(), gap, end);
for (Map.Entry<String, Object> entry : values) {
try {
f.add(entry.getKey(), Long.parseLong(entry.getValue().toString()));
} catch (NumberFormatException e) {
//Ignore for non-number responses which are already handled above
}
}
_facetDates.add(f);
}
}
}
}
_facetFields:所有的分层结果 使用 getFacetField(String name) 获得结果
_limitingFacets:facetFields中个数大于0的分层,使用getLimitingFacets()返回所有Count个数大于0的FacetField。
_facetDates:根据日期的分层结果 getFacetDate(String name)
例外,要使用Facet功能,除了设置 Field外,还需要将facet属性设置为true,默认是false的。
view plaincopy to clipboardprint?
params.set("facet", "true");
params.set("facet.field", "site_search");
params.set("facet.field", "kindtag_search");
1. FacetField 内嵌了 Count类,Count类保存了被分层出来的的 词 以及该词在搜有搜索出来的文档中出现的次数。
view plaincopy to clipboardprint?
package org.apache.solr.client.solrj.response;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.solr.client.solrj.util.ClientUtils;
/**
* A utility class to hold the facet response. It could use the NamedList container,
* but for JSTL, it is nice to have something that implements List so it can be iterated
*
* @version $Id: FacetField.java 638357 2008-03-18 13:12:27Z gsingers $
* @since solr 1.3
*/
public class FacetField implements Serializable
{
public static class Count implements Serializable
{
private String _name = null;
private long _count = 0;
// hang onto the FacetField for breadcrumb creation convenience
private FacetField _ff = null;
public Count( FacetField ff, String n, long c )
{
_name = n;
_count = c;
_ff = ff;
}
public String getName() {
return _name;
}
public void setName( String n )
{
_name = n;
}
public long getCount() {
return _count;
}
public void setCount( long c )
{
_count = c;
}
public FacetField getFacetField() {
return _ff;
}
@Override
public String toString()
{
return _name+" ("+_count+")";
}
public String getAsFilterQuery() {
if (_ff.getName().equals("facet_queries")) {
return _name;
}
return
ClientUtils.escapeQueryChars( _ff._name ) + ":" +
ClientUtils.escapeQueryChars( _name );
}
}
private String _name = null;
private List<Count> _values = null;
private String _gap = null;
private Date _end = null;
//.........
//.........方法
}
package org.apache.solr.client.solrj.response;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.solr.client.solrj.util.ClientUtils;
/**
* A utility class to hold the facet response. It could use the NamedList container,
* but for JSTL, it is nice to have something that implements List so it can be iterated
*
* @version $Id: FacetField.java 638357 2008-03-18 13:12:27Z gsingers $
* @since solr 1.3
*/
public class FacetField implements Serializable
{
public static class Count implements Serializable
{
private String _name = null;
private long _count = 0;
// hang onto the FacetField for breadcrumb creation convenience
private FacetField _ff = null;
public Count( FacetField ff, String n, long c )
{
_name = n;
_count = c;
_ff = ff;
}
public String getName() {
return _name;
}
public void setName( String n )
{
_name = n;
}
public long getCount() {
return _count;
}
public void setCount( long c )
{
_count = c;
}
public FacetField getFacetField() {
return _ff;
}
@Override
public String toString()
{
return _name+" ("+_count+")";
}
public String getAsFilterQuery() {
if (_ff.getName().equals("facet_queries")) {
return _name;
}
return
ClientUtils.escapeQueryChars( _ff._name ) + ":" +
ClientUtils.escapeQueryChars( _name );
}
}
private String _name = null;
private List<Count> _values = null;
private String _gap = null;
private Date _end = null;
//.........
//.........方法
}
一个FacetField实例拥有多个Count实例。