Solr的defType有dismax/edismax两种,这两种的区别,可参见:http://blog.csdn.net/duck_genuine/article/details/8060026

下面示例用于演示如下场景:

有一网站,在用户查询的结果中,需要按这样排序:

  1. VIP的付费信息需要排在免费信息的前头
  2. 点击率越高越靠前
  3. 发布时间越晚的越靠前

这样的查询排序使用普通的查询结果的Order by是做不到的,必需使用solr的defType。

做法:

1、先看schema.xml的定义:

  1. <?xml version="1.0" ?>
  2. <schema name="sample5" version="1.1">
  3.  
  4. <fieldtype name="string" class="solr.StrField" sortMissingLast="true" omitNorms="true"/>
  5. <fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/>
  6. <fieldType name="tdate" class="solr.TrieDateField" precisionStep="6" positionIncrementGap="0"/>
  7. <fieldType name="int" class="solr.TrieIntField" precisionStep="0" positionIncrementGap="0"/>
  8. <fieldType name="float" class="solr.TrieFloatField" precisionStep="0" positionIncrementGap="0"/>
  9. <fieldType name="double" class="solr.TrieDoubleField" precisionStep="0" positionIncrementGap="0"/>
  10. <fieldType name="boolean" class="solr.BoolField" sortMissingLast="true"/>
  11. <fieldtype name="binary" class="solr.BinaryField"/>
  12. <fieldType name="text_cn" class="solr.TextField">
  13. <analyzer type="index" class="org.wltea.analyzer.lucene.IKAnalyzer" useSmart="false" />
  14. <analyzer type="query" class="org.wltea.analyzer.lucene.IKAnalyzer" useSmart="true" />
  15. <analyzer>
  16. <tokenizer class="solr.KeywordTokenizerFactory"/>
  17. <filter class="solr.LowerCaseFilterFactory" ignoreCase="true"/>
  18. </analyzer>
  19. </fieldType>
  20.  
  21. <!-- general -->
  22. <fields>
  23. <field name="id" type="long" indexed="true" stored="true" multiValued="false" required="true"/>
  24. <field name="subject" type="text_cn" indexed="true" stored="true" />
  25. <field name="content" type="text_cn" indexed="true" stored="true" />
  26. <field name="regionId" type="int" indexed="true" stored="true" />
  27. <field name="region" type="text_cn" indexed="true" stored="true" />
  28. <field name="categoryId" type="int" indexed="true" stored="true" />
  29. <field name="category" type="text_cn" indexed="true" stored="true" />
  30. <field name="price" type="float" indexed="true" stored="true" />
  31. <field name="createTime" type="tdate" indexed="true" stored="true" />
  32. <field name="point" type="long" indexed="true" stored="true" />
  33. <field name="vip" type="boolean" indexed="true" stored="true" />
  34. <field name="_version_" type="long" indexed="true" stored="true"/>
  35. <field name="searchText" type="text_cn" indexed="true" stored="false" multiValued="true" />
  36. </fields>
  37.  
  38. <copyField source="subject" dest="searchText" />
  39. <copyField source="content" dest="searchText" />
  40. <copyField source="region" dest="searchText" />
  41. <copyField source="category" dest="searchText" />
  42.  
  43. <!-- field to use to determine and enforce document uniqueness. -->
  44. <uniqueKey>id</uniqueKey>
  45.  
  46. <!-- field for the QueryParser to use when an explicit fieldname is absent -->
  47. <defaultSearchField>searchText</defaultSearchField>
  48.  
  49. <!-- SolrQueryParser configuration: defaultOperator="AND|OR" -->
  50. <solrQueryParser defaultOperator="AND"/>
  51. </schema>

说明:

a)里头定义了一个copyField:searchText,此字段为:subject+content+region+category,并把这个字段设置为默认查询字段。意思是查询时,默认查询四个字段的内容。

b)把solrQueryParser设置为AND,事实上,大多情况下,我们是习惯使用AND为条件查询,而非OR

c)text_cn字段类型中的:useSmart

  1. <analyzer type="index" class="org.wltea.analyzer.lucene.IKAnalyzer" useSmart="false" />
  2. <analyzer type="query" class="org.wltea.analyzer.lucene.IKAnalyzer" useSmart="true" />

意思是:useSmart =true ,分词器使用智能切分策略, =false则使用细粒度切分。详细,可下载IK分词器的源码看看。

2、加入一个查询Handler到solrconfig.xml的<config/>当中:

  1. <requestHandler name="/browse" class="solr.SearchHandler" default="true" >
  2. <lst name="defaults">
  3. <str name="defType">edismax</str>
  4. <str name="bf">
  5. sum(linear(vip,1000,0),linear(sqrt(log(linear(point,1,2))),100,0),sqrt(log(ms(createTime))))
  6. </str>
  7. <!--<str name="pf">
  8. searchText
  9. </str>
  10. <str name="qf">
  11. subject^1 content^0.8
  12. </str>-->
  13. </lst>
  14. </requestHandler>

说明:

a)上面的default="true"意思为设置为默认的查询handler(记得把原standard中的default="true"删除掉)

b)见已经被注释的这段:

  1. <!--<str name="pf">
  2. searchText
  3. </str>
  4. <str name="qf">
  5. subject^1 content^0.8
  6. </str>-->

这是简单的不使用bf的排序加权方式,可以用于应付简单的排序,具体pf/qf的使用,可以上网上搜搜应用。这里演示的功能相对“复杂”,不适用它。

c)见这句公式:

  1. 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以内

以上三个值相加得出最统权重分从高到低排序

3、Java bean:

  1. package com.my.entity;
  2.  
  3. import java.util.Date;
  4.  
  5. import org.apache.solr.client.solrj.beans.Field;
  6.  
  7. public class Item {
  8. @Field
  9. private long id;
  10. @Field
  11. private String subject;
  12. @Field
  13. private String content;
  14. @Field
  15. private int regionId;
  16. @Field
  17. private int categoryId;
  18. @Field
  19. private float price;
  20. @Field
  21. private Date createTime;
  22. @Field
  23. private long point;
  24. @Field
  25. private boolean vip;
  26.  
  27. public long getId() {
  28. return id;
  29. }
  30. public void setId(long id) {
  31. this.id = id;
  32. }
  33. public String getSubject() {
  34. return subject;
  35. }
  36. public void setSubject(String subject) {
  37. this.subject = subject;
  38. }
  39. public String getContent() {
  40. return content;
  41. }
  42. public void setContent(String content) {
  43. this.content = content;
  44. }
  45. public int getRegionId() {
  46. return regionId;
  47. }
  48. public void setRegionId(int regionId) {
  49. this.regionId = regionId;
  50. }
  51. public int getCategoryId() {
  52. return categoryId;
  53. }
  54. public void setCategoryId(int categoryId) {
  55. this.categoryId = categoryId;
  56. }
  57. public float getPrice() {
  58. return price;
  59. }
  60. public void setPrice(float price) {
  61. this.price = price;
  62. }
  63. public Date getCreateTime() {
  64. return createTime;
  65. }
  66. public void setCreateTime(Date createTime) {
  67. this.createTime = createTime;
  68. }
  69. public long getPoint() {
  70. return point;
  71. }
  72. public void setPoint(long point) {
  73. this.point = point;
  74. }
  75. public boolean isVip() {
  76. return vip;
  77. }
  78. public void setVip(boolean vip) {
  79. this.vip = vip;
  80. }
  81. }

4、Java测试代码:

  1. package com.my.solr;
  2.  
  3. import java.io.IOException;
  4. import java.util.ArrayList;
  5. import java.util.Calendar;
  6. import java.util.Date;
  7. import java.util.HashMap;
  8. import java.util.Iterator;
  9. import java.util.List;
  10.  
  11. import org.apache.solr.client.solrj.SolrQuery;
  12. import org.apache.solr.client.solrj.SolrQuery.ORDER;
  13. import org.apache.solr.client.solrj.SolrQuery.SortClause;
  14. import org.apache.solr.client.solrj.SolrServerException;
  15. import org.apache.solr.client.solrj.impl.HttpSolrServer;
  16. import org.apache.solr.client.solrj.impl.XMLResponseParser;
  17. import org.apache.solr.client.solrj.response.FacetField;
  18. import org.apache.solr.client.solrj.response.FacetField.Count;
  19. import org.apache.solr.client.solrj.response.QueryResponse;
  20. import org.apache.solr.common.params.AnalysisParams;
  21. import org.apache.solr.common.params.CommonParams;
  22. import org.apache.solr.common.params.FacetParams;
  23. import org.apache.solr.common.util.NamedList;
  24. import org.apache.solr.common.util.SimpleOrderedMap;
  25.  
  26. import com.my.entity.Item;
  27.  
  28. public class TestSolr {
  29. private static HashMap<Integer, String> mapRegion = new HashMap<Integer, String>();
  30. private static HashMap<Integer, String> mapCategory = new HashMap<Integer, String>();
  31.  
  32. @SuppressWarnings("unchecked")
  33. public static void main(String[] args) throws IOException,
  34. SolrServerException {
  35. // ------------------------------------------------------
  36. // Set map
  37. // ------------------------------------------------------
  38. mapRegion.put(1, "罗湖区");
  39. mapRegion.put(2, "南山区");
  40. mapRegion.put(3, "龙岗区");
  41. mapRegion.put(4, "福田区");
  42. mapCategory.put(1, "单间");
  43. mapCategory.put(2, "2房1厅");
  44. mapCategory.put(3, "3房2厅");
  45. mapCategory.put(4, "1房1厅");
  46.  
  47. String url = "http://localhost:8983/solr/sample5";
  48. HttpSolrServer core = new HttpSolrServer(url);
  49. core.setMaxRetries(1);
  50. core.setConnectionTimeout(5000);
  51. core.setParser(new XMLResponseParser()); // binary parser is used by
  52. // default
  53. core.setSoTimeout(1000); // socket read timeout
  54. core.setDefaultMaxConnectionsPerHost(100);
  55. core.setMaxTotalConnections(100);
  56. core.setFollowRedirects(false); // defaults to false
  57. core.setAllowCompression(true);
  58.  
  59. // ------------------------------------------------------
  60. // remove all data
  61. // ------------------------------------------------------
  62. core.deleteByQuery("*:*");
  63. List<Item> items = new ArrayList<Item>();
  64. items.add(makeItem(items.size() + 1, "龙城公寓一房一厅", "豪华城城公寓1房1厅,拧包入住", 1, 1, 1200f, 10, false));
  65. items.add(makeItem(items.size() + 1, "兴新宿舍楼 1室0厅", " 中等装修 招女性合租", 1, 1, 1000f, 11, false));
  66. items.add(makeItem(items.size() + 1, "西丽新屋村新宿舍楼单间", " 无敌装修只招女性", 2, 1, 1000f, 2, true));
  67. items.add(makeItem(items.size() + 1, "大芬村信和爱琴居地铁口2房1厅", " 地铁口 + 出行便利=居家首选", 3, 2, 2000f, 5, false));
  68. items.add(makeItem(items.size() + 1, "龙岗富豪花园3房2厅出租", " 离地铁口只要5分钟,快来秒杀吧", 3, 3, 4500f, 21, true));
  69. items.add(makeItem(items.size() + 1, "海景房园3房2厅出租", "海景房园出租,无敌海景,可以看到伦敦", 4, 3, 8500f, 12, false));
  70. items.add(makeItem(items.size() + 1, "天域花园1房1厅", "天域花园,男女不限,入住免水电一月", 2, 4, 1500f, 13, true));
  71. items.add(makeItem(items.size() + 1, "神一样的漂亮,玉馨山庄3房2厅", "心动不如行动,拧包即可入住,来吧!", 1, 3, 9500f, 8, false));
  72. items.add(makeItem(items.size() + 1, "玉馨山庄2房1厅,情侣最爱", "宅男宅女快来吧只要2500,走过路过,别再错过", 1, 2, 2500f, 5, false));
  73. items.add(makeItem(items.size() + 1, "天域花园3房2厅", "天域花园出租,都来看看,都来瞄瞄,3房出租只要7500.", 4, 3, 7500f, 6, true));
  74. items.add(makeItem(items.size() + 1, "深都花园出租3房2厅", "找爱干净的人氏,全新装修", 4, 3, 5200f, 31, false));
  75. items.add(makeItem(items.size() + 1, "This is Mobile test", "haha Hello world!", 4, 3, 1200f, 31, false));
  76. core.addBeans(items);
  77. // commit
  78. core.commit();
  79.  
  80. // ------------------------------------------------------
  81. // Set search text
  82. // ------------------------------------------------------
  83. String searchText = AnalysisSearchText(core, "出租花园"); //subject:*出租* && price:[1000 TO 8000]
  84. System.out.println("Search Text:" + searchText);
  85.  
  86. // ------------------------------------------------------
  87. // Set query text
  88. // ------------------------------------------------------
  89. String queryText = searchText + "&& price:[1000 TO 8000]";
  90. System.out.println("Query Text:" + queryText);
  91.  
  92. // ------------------------------------------------------
  93. // search
  94. // ------------------------------------------------------
  95. SolrQuery query = new SolrQuery();
  96. query.setQuery(queryText);
  97. query.setStart(0); // query的开始行数(分页使用)
  98. query.setRows(100); // query的返回行数(分页使用)
  99. query.setFacet(true); // 设置使用facet
  100. query.setFacetMinCount(0); // 设置facet最少的统计数量
  101. query.setFacetLimit(10); // facet结果的返回行数
  102. query.addFacetField("categoryId", "regionId"); // facet的字段
  103. query.setFacetSort(FacetParams.FACET_SORT_COUNT);
  104. //query.addSort(new SortClause("id", ORDER.asc)); // 排序
  105. query.setRequestHandler("/browse");
  106. QueryResponse response = core.query(query);
  107. List<Item> items_rep = response.getBeans(Item.class);
  108. List<FacetField> facetFields = response.getFacetFields();
  109. // 因为上面的start和rows均设置为0,所以这里不会有query结果输出
  110. System.out.println("--------------------");
  111. System.out.println("Search result:");
  112. for (Item item : items_rep) {
  113. System.out.println("id=" + item.getId() + "\tsubject=" + item.getSubject()
  114. + "\tregion=" + mapRegion.get(item.getRegionId())
  115. + "\tcategory=" + mapCategory.get(item.getCategoryId())
  116. + "\tprice=" + item.getPrice());
  117. }
  118. // 打印所有facet
  119. for (FacetField ff : facetFields) {
  120. System.out.println("--------------------");
  121. System.out.println("name=" + ff.getName() + "\tcount=" + ff.getValueCount());
  122. System.out.println("--------------------");
  123. switch (ff.getName()) {
  124. case "regionId":
  125. printOut(mapRegion, ff.getValues());
  126. break;
  127. case "categoryId":
  128. printOut(mapCategory, ff.getValues());
  129. break;
  130. }
  131. }
  132. }
  133.  
  134. @SuppressWarnings({ "rawtypes" })
  135. private static void printOut(HashMap map, List<Count> counts) {
  136. for (Count count : counts) {
  137. System.out.println("name=" + map.get(Integer.parseInt(count.getName())) + "\tcount=" + count.getCount());
  138. }
  139. System.out.println("--------------------");
  140. }
  141.  
  142. private static Item makeItem(long id, String subject, String content, int regionId, int categoryId, float price,
  143. long point, boolean vip) {
  144. Calendar cale = Calendar.getInstance();
  145. cale.setTime(new Date());
  146. cale.add(Calendar.DATE, (int)id);
  147. Item item = new Item();
  148. item.setId(id);
  149. item.setSubject(subject);
  150. item.setContent(content);
  151. item.setRegionId(regionId);
  152. item.setCategoryId(categoryId);
  153. item.setPrice(price);
  154. item.setCreateTime(cale.getTime());
  155. item.setPoint(point);
  156. item.setVip(vip);
  157. return item;
  158. }
  159.  
  160. @SuppressWarnings("unchecked")
  161. /**
  162. * 重新将需要查询的文本内容解析成分词
  163. * @param core
  164. * @param searchText
  165. * @return
  166. * @throws SolrServerException
  167. */
  168. private static String AnalysisSearchText(HttpSolrServer core, String searchText) throws SolrServerException {
  169. StringBuilder strSearchText = new StringBuilder();
  170. final String STR_FIELD_TYPE = "text_cn";
  171. SolrQuery queryAnalysis = new SolrQuery();
  172. queryAnalysis.add(CommonParams.QT, "/analysis/field"); // query type
  173. queryAnalysis.add(AnalysisParams.FIELD_VALUE, searchText);
  174. queryAnalysis.add(AnalysisParams.FIELD_TYPE, STR_FIELD_TYPE);
  175. QueryResponse responseAnalysis = core.query(queryAnalysis);
  176. //对响应进行解析
  177. NamedList<Object> analysis = (NamedList<Object>) responseAnalysis.getResponse().get("analysis");// analysis node
  178. NamedList<Object> field_types = (NamedList<Object>) analysis.get("field_types");// field_types node
  179. NamedList<Object> fieldType = (NamedList<Object>) field_types.get(STR_FIELD_TYPE);// text_cn node
  180. NamedList<Object> index = (NamedList<Object>) fieldType.get("index");// index node
  181. List<SimpleOrderedMap<String>> list = (ArrayList<SimpleOrderedMap<String>>)index.get("org.wltea.analyzer.lucene.IKTokenizer");// tokenizer node
  182. // 在每个词条中间加上空格,为每个词条进行或运算
  183. for(Iterator<SimpleOrderedMap<String>> iter = list.iterator(); iter.hasNext();)
  184. {
  185. strSearchText.append(iter.next().get("text") + " ");
  186. }
  187. return strSearchText.toString();
  188. }
  189. }

说明:

a)AnalysisSearchText(...)方法:此方法会把需要查询的语句先使用分词分析,如上例子“出租花园”,调用AnalysisSearchText(...)后,会得到“出租 花园”,会把两个词分拆成以空格分隔的字符串。不然solr会以“出租花园”整体做为词做查询而得不到结果。

b)使用自定义的Handler,需要在代码中加入这句:

  1. query.setRequestHandler("/browse");

对应的是solrconfig.xml中的requestHandler的:/browse

5、运行结果:

或者使用solr的query查询查看结果:

solr defType查询权重排序的更多相关文章

  1. [solr] - defType - 查询权重排序

    Solr的defType有dismax/edismax两种,这两种的区别,可参见:http://blog.csdn.net/duck_genuine/article/details/8060026 下 ...

  2. solr特点三: defType(查询权重排序)

    Solr的defType有dismax/edismax两种,这两种的区别,可参见:http://blog.csdn.net/duck_genuine/article/details/8060026 e ...

  3. solr入门之权重排序方法初探之使用edismax改变权重

    做搜索引擎避免不了排序问题,当排序没有要求时,solr有自己的排序打分机制及sorce字段 1.无特殊排序要求时,根据查询相关度来进行排序(solr自身规则) 2.当涉及到一个字段来进行相关度排序时, ...

  4. 【solr】之solr界面查询返回距离并排序

    使用solr界面查询 {!geofilt}距离函数 star:[4 TO 5]星级排序 geodist() desc 距离排序 pt :31.221717,121.580891 sfield:loca ...

  5. dedecms 按权重排序不准或BUG的处理方法

    dede:list 的方法 1.找到"根目录\include\arc.listview.class.php"文件. 2.修改代码:在文件第727行处添加按weight排序判断代码( ...

  6. DedeCMS让{dede:list}标签支持weight权重排序

    1.找到"根目录\include\arc.listview.class.php"文件. 2.修改代码:在文件第727行处添加按weight排序判断代码(红色部分为新添加代码). / ...

  7. 【转】Solr客户端查询参数总结

    今天还是不会涉及到.Net和数据库操作,主要还是总结Solr 的查询参数,还是那句话,只有先明白了solr的基础内容和查询语法,后续学习solr 的C#和数据库操作,都是水到渠成的事.这里先列出sol ...

  8. dede:list及dede:arclist 按权重排序的方法

    有时我们需要做文章排名,比如指定第一名到第三名在前面,这样就用到这个权重排序方法.稍改下就可以完美支持.. dede:list 的方法 1 找到"根目录\include\arc.listvi ...

  9. 如何大幅优化solr的查询性能(转)

    提升软件性能,通常喜欢去调整各种启动参数,这没有多大意义,小伎俩. 性能优化要从架构和策略入手,才有可能得到较大的收益 Solr的查询是基于Field的,以Field为基本单元,例如一个文章站要索引 ...

随机推荐

  1. Ansible 常用模块之ping(四)

    一.ping 模块 1.用途: 测试主机之间的连通性: 2.关键字:ping 3.参数:无 4.用法: ansible all -m ping 命令简单,测试所有服务器是否与控制机网络连通:

  2. 洛谷 5291 [十二省联考2019]希望(52分)——思路+树形DP

    题目:https://www.luogu.org/problemnew/show/P5291 考场上写了 16 分的.不过只得了 4 分. 对于一个救援范围,其中合法的点集也是一个连通块. 2n 枚举 ...

  3. java直接量(literal)

    直接量就是代码中直接使用的值,如 int i = 7;  char c = 'a'; boolean b = false;  7.'a'.false就是直接量. java有三种类型的直接量:基本类型. ...

  4. java自动装箱的一个例子

    Object obj = 56; int i = (Integer)obj; 第一行等价于: Object obj = Integer.valueOf(56);      Integer.valueO ...

  5. windows下安装redis以及测试 --转载自http://www.cnblogs.com/lpyan/p/5608333.html

    redis加入到Windows 服务 以下方式,需要在redis-2.8.24下执行:http://download.csdn.net/download/feiliua/9425770 ,另外php的 ...

  6. 错误 Run-time error nnn at xxxx; 错误

      出现runtime error临时解决办法,于注册表位置中找到如下键值HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Gdiplus,然后把键DisableTIFFCo ...

  7. java中经常使用的Swing组件总结

    1.按钮(Jbutton) Swing中的按钮是Jbutton,它是javax.swing.AbstracButton类的子类,swing中的按钮可以显示图像,并且可以将按钮设置为窗口的默认图标,而且 ...

  8. Centos7 安装sz,rz命令

    yum install lrzsz 我记得以前某个我敬佩的人说过压缩分很多种,有空,补充这篇笔记.加油~

  9. 客户端负载均衡Feign之三:Feign补充

    在spring Cloud Netflix栈中,各个微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就必须使用HTTP客户端.我们可以使用JDK原生的URLConnection.Ap ...

  10. ACM主要算法

    ACM主要算法ACM主要算法介绍 初期篇 一.基本算法(1)枚举(poj1753, poj2965)(2)贪心(poj1328, poj2109, poj2586)(3)递归和分治法(4)递推(5)构 ...