下面示例用于演示如下场景:
有一网站,在用户查询的结果中,需要按这样排序:
- VIP的付费信息需要排在免费信息的前头
- 点击率越高越靠前
- 发布时间越晚的越靠前
这样的查询排序使用普通的查询结果的Order by是做不到的,必需使用solr的defType。
做法:
1、先看schema.xml的定义:
<?xml version="1.0" ?>
<schema name="sample5" version="1.1">
<fieldtype name="string" class="solr.StrField" sortMissingLast="true" omitNorms="true"/>
<fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="tdate" class="solr.TrieDateField" precisionStep="6" positionIncrementGap="0"/>
<fieldType name="int" class="solr.TrieIntField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="float" class="solr.TrieFloatField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="double" class="solr.TrieDoubleField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="boolean" class="solr.BoolField" sortMissingLast="true"/>
<fieldtype name="binary" class="solr.BinaryField"/>
<fieldType name="text_cn" class="solr.TextField">
<analyzer type="index" class="org.wltea.analyzer.lucene.IKAnalyzer" useSmart="false" />
<analyzer type="query" class="org.wltea.analyzer.lucene.IKAnalyzer" useSmart="true" />
<analyzer>
<tokenizer class="solr.KeywordTokenizerFactory"/>
<filter class="solr.LowerCaseFilterFactory" ignoreCase="true"/>
</analyzer>
</fieldType>
<!-- general -->
<fields>
<field name="id" type="long" indexed="true" stored="true" multiValued="false" required="true"/>
<field name="subject" type="text_cn" indexed="true" stored="true" />
<field name="content" type="text_cn" indexed="true" stored="true" />
<field name="regionId" type="int" indexed="true" stored="true" />
<field name="region" type="text_cn" indexed="true" stored="true" />
<field name="categoryId" type="int" indexed="true" stored="true" />
<field name="category" type="text_cn" indexed="true" stored="true" />
<field name="price" type="float" indexed="true" stored="true" />
<field name="createTime" type="tdate" indexed="true" stored="true" />
<field name="point" type="long" indexed="true" stored="true" />
<field name="vip" type="boolean" indexed="true" stored="true" />
<field name="_version_" type="long" indexed="true" stored="true"/>
<field name="searchText" type="text_cn" indexed="true" stored="false" multiValued="true" />
</fields>
<copyField source="subject" dest="searchText" />
<copyField source="content" dest="searchText" />
<copyField source="region" dest="searchText" />
<copyField source="category" dest="searchText" />
<!-- field to use to determine and enforce document uniqueness. -->
<uniqueKey>id</uniqueKey>
<!-- field for the QueryParser to use when an explicit fieldname is absent -->
<defaultSearchField>searchText</defaultSearchField>
<!-- SolrQueryParser configuration: defaultOperator="AND|OR" -->
<solrQueryParser defaultOperator="AND"/>
</schema>
说明:
a)里头定义了一个copyField:searchText,此字段为:subject+content+region+category,并把这个字段设置为默认查询字段。意思是查询时,默认查询四个字段的内容。
b)把solrQueryParser设置为AND,事实上,大多情况下,我们是习惯使用AND为条件查询,而非OR
c)text_cn字段类型中的:useSmart
<analyzer type="index" class="org.wltea.analyzer.lucene.IKAnalyzer" useSmart="false" />
<analyzer type="query" class="org.wltea.analyzer.lucene.IKAnalyzer" useSmart="true" />
意思是:useSmart =true ,分词器使用智能切分策略, =false则使用细粒度切分。详细,可下载IK分词器的源码看看。
2、加入一个查询Handler到solrconfig.xml的<config/>当中:
<requestHandler name="/browse" class="solr.SearchHandler" default="true" >
<lst name="defaults">
<str name="defType">edismax</str>
<str name="bf">
sum(linear(vip,1000,0),linear(sqrt(log(linear(point,1,2))),100,0),sqrt(log(ms(createTime))))
</str>
<!--<str name="pf">
searchText
</str>
<str name="qf">
subject^1 content^0.8
</str>-->
</lst>
</requestHandler>
说明:
a)上面的default="true"意思为设置为默认的查询handler(记得把原standard中的default="true"删除掉)
b)见已经被注释的这段:
<!--<str name="pf">
searchText
</str>
<str name="qf">
subject^1 content^0.8
</str>-->
这是简单的不使用bf的排序加权方式,可以用于应付简单的排序,具体pf/qf的使用,可以上网上搜搜应用。这里演示的功能相对“复杂”,不适用它。
c)见这句公式:
sum(linear(vip,1000,0),linear(sqrt(log(linear(point,1,2))),100,0),sqrt(log(ms(createTime))))
公式中的函数定义和意思,可以参考:
官方文档:
http://wiki.apache.org/solr/FunctionQuery
中文说明:
http://mxsfengg.iteye.com/blog/352191
这里的函数意思是:
- 如果是vip信息=值+1000,非vip信息=值+0
- 点击率(point)的值范围为:50~500之间
- 发布时间(createTime)值范围为:50以内
以上三个值相加得出最统权重分从高到低排序