Solr 深度分页

转载请出自出处:http://eksliang.iteye.com/blog/2148370

作者:eksliang(ickes) blg:http://eksliang.iteye.com/

概述

长期以来,我们一直有一个深分页问题。如果直接跳到很靠后的页数,查询速度会比较慢。这是因为Solr的需要为查询从开始遍历所有数据。直到Solr的4.7这个问题一直没有一个很好的解决方案。直到solr4.7引入了游标才解决这个问题。

 

问题

深分页的问题是很清楚。Solr必须为返回的搜索结果准备一个列表,并返回它的一部分。如果该部分来源于该列表的前面并不难。但如果我们想返回第10000页(每页20条记录)的数据,Solr需要准备一个包含大小为200000(10000 * 20)的列表。这样,它不仅需要时间,还需要内存。像我们现在生产上的历史数据达到了6个亿的数据,如果直接跳转到最后一页,必定内存溢出。

 

solr4.7是怎么解决这个问题的?

答:Solr 4.7的发布改变了这一状况,引入了游标的概念。游标是一个动态结构,不需要存储在服务器上。游标包含了查询的结果的偏移量,因此,Solr的不再需要每次从头开始遍历结果直到我们想要的记录,游标的功能可以大幅提升深翻页的性能。

 

用法

游标的使用非常简单。在第一个查询中,我们需要传递一个额外的参数- cursorMark = *,告诉Solr返回游标。在返回中除了搜索结果,我们还可以得到nextCursorMark信息。看看下面这个例子。

  1. http://192.168.238.133:8080/solr/collection1/select?q=*:*&rows=3&sort=price desc,id asc&cursorMark=*  
http://192.168.238.133:8080/solr/collection1/select?q=*:*&rows=3&sort=price desc,id asc&cursorMark=*

 返回结果如下:

 

  1. <response>  
  2. <lst name="responseHeader">  
  3. <int name="status">0</int>  
  4. <int name="QTime">186</int>  
  5. <lst name="params">  
  6. <str name="sort">price desc,id asc</str>  
  7. <str name="q">*:*</str>  
  8. <str name="cursorMark">*</str>  
  9. <str name="rows">3</str>  
  10. </lst>  
  11. </lst>  
  12. <result name="response" numFound="4160002" start="0">  
  13. <doc>  
  14. <str name="id">a004180000</str>  
  15. <str name="name">ickes_4180000</str>  
  16. <float name="price">5180000.0</float>  
  17. <str name="price_c">5180000.0,USD</str>  
  18. <str name="url">www.eksliang.iteye4180000</str>  
  19. <long name="_version_">1483095619858857993</long>  
  20. </doc>  
  21. <doc>  
  22. <str name="id">a004179999</str>  
  23. <str name="name">ickes_4179999</str>  
  24. <float name="price">5179999.0</float>  
  25. <str name="price_c">5179999.0,USD</str>  
  26. <str name="url">www.eksliang.iteye4179999</str>  
  27. <long name="_version_">1483095619858857992</long>  
  28. </doc>  
  29. <doc>  
  30. <str name="id">a004179998</str>  
  31. <str name="name">ickes_4179998</str>  
  32. <float name="price">5179998.0</float>  
  33. <str name="price_c">5179998.0,USD</str>  
  34. <str name="url">www.eksliang.iteye4179998</str>  
  35. <long name="_version_">1483095619858857991</long>  
  36. </doc>  
  37. </result>  
  38. <str name="nextCursorMark">AoIISp4UvCphMDA0MTc5OTk4</str>  
  39. </response>  
<response>
<lst name="responseHeader">
<int name="status">0</int>
<int name="QTime">186</int>
<lst name="params">
<str name="sort">price desc,id asc</str>
<str name="q">*:*</str>
<str name="cursorMark">*</str>
<str name="rows">3</str>
</lst>
</lst>
<result name="response" numFound="4160002" start="0">
<doc>
<str name="id">a004180000</str>
<str name="name">ickes_4180000</str>
<float name="price">5180000.0</float>
<str name="price_c">5180000.0,USD</str>
<str name="url">www.eksliang.iteye4180000</str>
<long name="_version_">1483095619858857993</long>
</doc>
<doc>
<str name="id">a004179999</str>
<str name="name">ickes_4179999</str>
<float name="price">5179999.0</float>
<str name="price_c">5179999.0,USD</str>
<str name="url">www.eksliang.iteye4179999</str>
<long name="_version_">1483095619858857992</long>
</doc>
<doc>
<str name="id">a004179998</str>
<str name="name">ickes_4179998</str>
<float name="price">5179998.0</float>
<str name="price_c">5179998.0,USD</str>
<str name="url">www.eksliang.iteye4179998</str>
<long name="_version_">1483095619858857991</long>
</doc>
</result>
<str name="nextCursorMark">AoIISp4UvCphMDA0MTc5OTk4</str>
</response>
 

 

   我们看到,除了平时返回的结果外,还多了一个游标数据nextCursorMark,使用这个值作为我们翻下一页的参数。

在这个基础上要得到下一页数据怎么办:让cursorMark的值等于上次返回的nextCursorMark

例如现在的下一页是这样的

  1. http://192.168.238.133:8080/solr/collection1/select?q=*:*&rows=3&sort=price desc,id asc&cursorMark=AoIISp4UvCphMDA0MTc5OTk4  
http://192.168.238.133:8080/solr/collection1/select?q=*:*&rows=3&sort=price desc,id asc&cursorMark=AoIISp4UvCphMDA0MTc5OTk4

 这个时候就可以得到下一页的数据,数据如下:

  1. <response>  
  2. <lst name="responseHeader">  
  3. <int name="status">0</int>  
  4. <int name="QTime">234</int>  
  5. <lst name="params">  
  6. <str name="sort">price desc,id asc</str>  
  7. <str name="q">*:*</str>  
  8. <str name="cursorMark">AoIISp4UvCphMDA0MTc5OTk4</str>  
  9. <str name="rows">3</str>  
  10. </lst>  
  11. </lst>  
  12. <result name="response" numFound="4160002" start="0">  
  13. <doc>  
  14. <str name="id">a004179997</str>  
  15. <str name="name">ickes_4179997</str>  
  16. <float name="price">5179997.0</float>  
  17. <str name="price_c">5179997.0,USD</str>  
  18. <str name="url">www.eksliang.iteye4179997</str>  
  19. <long name="_version_">1483095619858857990</long>  
  20. </doc>  
  21. <doc>  
  22. <str name="id">a004179996</str>  
  23. <str name="name">ickes_4179996</str>  
  24. <float name="price">5179996.0</float>  
  25. <str name="price_c">5179996.0,USD</str>  
  26. <str name="url">www.eksliang.iteye4179996</str>  
  27. <long name="_version_">1483095619858857989</long>  
  28. </doc>  
  29. <doc>  
  30. <str name="id">a004179995</str>  
  31. <str name="name">ickes_4179995</str>  
  32. <float name="price">5179995.0</float>  
  33. <str name="price_c">5179995.0,USD</str>  
  34. <str name="url">www.eksliang.iteye4179995</str>  
  35. <long name="_version_">1483095619858857988</long>  
  36. </doc>  
  37. </result>  
  38. <str name="nextCursorMark">AoIISp4UtiphMDA0MTc5OTk1</str>  
  39. </response>  
<response>
<lst name="responseHeader">
<int name="status">0</int>
<int name="QTime">234</int>
<lst name="params">
<str name="sort">price desc,id asc</str>
<str name="q">*:*</str>
<str name="cursorMark">AoIISp4UvCphMDA0MTc5OTk4</str>
<str name="rows">3</str>
</lst>
</lst>
<result name="response" numFound="4160002" start="0">
<doc>
<str name="id">a004179997</str>
<str name="name">ickes_4179997</str>
<float name="price">5179997.0</float>
<str name="price_c">5179997.0,USD</str>
<str name="url">www.eksliang.iteye4179997</str>
<long name="_version_">1483095619858857990</long>
</doc>
<doc>
<str name="id">a004179996</str>
<str name="name">ickes_4179996</str>
<float name="price">5179996.0</float>
<str name="price_c">5179996.0,USD</str>
<str name="url">www.eksliang.iteye4179996</str>
<long name="_version_">1483095619858857989</long>
</doc>
<doc>
<str name="id">a004179995</str>
<str name="name">ickes_4179995</str>
<float name="price">5179995.0</float>
<str name="price_c">5179995.0,USD</str>
<str name="url">www.eksliang.iteye4179995</str>
<long name="_version_">1483095619858857988</long>
</doc>
</result>
<str name="nextCursorMark">AoIISp4UtiphMDA0MTc5OTk1</str>
</response>

 这个时候进一步查询就变得相当简单了,直接

  1. http://192.168.238.133:8080/solr/collection1/select?q=*:*&rows=3&sort=price desc,id asc&cursorMark=AoIISp4UtiphMDA0MTc5OTk1  
http://192.168.238.133:8080/solr/collection1/select?q=*:*&rows=3&sort=price desc,id asc&cursorMark=AoIISp4UtiphMDA0MTc5OTk1

 

solrj对Solr Deep Paging的支持

直接上代码 

  1. static void deepPaging() throws SolrServerException{  
  2.         HttpSolrServer server = new HttpSolrServer("http://192.168.238.133:8080/solr/collection1");  
  3.         server.setSoTimeout(10000);  
  4.         server.setConnectionTimeout(10000);  
  5.         server.setDefaultMaxConnectionsPerHost(12);  
  6.         server.setAllowCompression(true);  
  7.         SolrQuery query = new SolrQuery();  
  8.         query.setQuery( "*:*" );  
  9.         query.setRows(4);  
  10.         query.addSort("price",ORDER.desc).addSort("id", ORDER.desc);  
  11.         query.set(CursorMarkParams.CURSOR_MARK_PARAM, "*");  
  12.         QueryResponse rsp = server.query( query );  
  13.         List<CursorMark> beans = rsp.getBeans(CursorMark.class);  
  14.         System.out.println(rsp.getNextCursorMark());//得到下一个游标  
  15.         for (CursorMark cursorMark : beans) {  
  16.             System.out.println(cursorMark);  
  17.         }         
  18.     }  
static void deepPaging() throws SolrServerException{
		HttpSolrServer server = new HttpSolrServer("http://192.168.238.133:8080/solr/collection1");
		server.setSoTimeout(10000);
		server.setConnectionTimeout(10000);
		server.setDefaultMaxConnectionsPerHost(12);
		server.setAllowCompression(true);
		SolrQuery query = new SolrQuery();
	    query.setQuery( "*:*" );
	    query.setRows(4);
	    query.addSort("price",ORDER.desc).addSort("id", ORDER.desc);
	    query.set(CursorMarkParams.CURSOR_MARK_PARAM, "*");
	    QueryResponse rsp = server.query( query );
	    List<CursorMark> beans = rsp.getBeans(CursorMark.class);
	    System.out.println(rsp.getNextCursorMark());//得到下一个游标
		for (CursorMark cursorMark : beans) {
			System.out.println(cursorMark);
		}		
	}

 返回结果如下:

  1. AoIISp4UuiphMDA0MTc5OTk3  
  2. CursorMark [id=a004180000, name=ickes_4180000, price=5180000.0, url=www.eksliang.iteye4180000]  
  3. CursorMark [id=a004179999, name=ickes_4179999, price=5179999.0, url=www.eksliang.iteye4179999]  
  4. CursorMark [id=a004179998, name=ickes_4179998, price=5179998.0, url=www.eksliang.iteye4179998]  
  5. CursorMark [id=a004179997, name=ickes_4179997, price=5179997.0, url=www.eksliang.iteye4179997]  
AoIISp4UuiphMDA0MTc5OTk3
CursorMark [id=a004180000, name=ickes_4180000, price=5180000.0, url=www.eksliang.iteye4180000]
CursorMark [id=a004179999, name=ickes_4179999, price=5179999.0, url=www.eksliang.iteye4179999]
CursorMark [id=a004179998, name=ickes_4179998, price=5179998.0, url=www.eksliang.iteye4179998]
CursorMark [id=a004179997, name=ickes_4179997, price=5179997.0, url=www.eksliang.iteye4179997]

 

 

   参考:http://solr.pl/en/2014/03/10/solr-4-7-efficient-deep-paging/

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值