1. 程式人生 > >Solr遊標查詢提高翻頁效率

Solr遊標查詢提高翻頁效率

ppm 所有 println 52.0 1.0 extc pos sca stat

使用cursorMark深分頁

1、Solr4.7+

2、start=0(一直等於0),rows=6(需要返回的記錄條目)

3、第一次請求cursorMark=*,下一次請求用上次請求返回的cursortMark值

長期以來,我們一直有一個深分頁問題。如果直接跳到很靠後的頁數,查詢速度會比較慢。這是因為Solr的需要為查詢從開始遍歷所有數據。直到Solr的4.7這個問題一直沒有一個很好的解決方案。與最近發布的Solr的版本中,Solr使用了所謂的遊標大幅度提高深翻頁的性能。

問題
深分頁的問題是很清楚。Solr必須為返回的搜索結果準備一個列表,並返回它的一部分。如果該部分來源於該列表的前面並不難。但如果我們想返回第10000頁(每頁20條記錄)的數據,Solr需要準備一個包含大小為200000(10000 * 20)的列表。這樣,它不僅需要時間,還需要內存。

令人高興的是,Solr 4.7的發布改變了這一狀況,引入了遊標的概念。遊標是一個動態結構,不需要存儲在服務器上。遊標包含了查詢的結果的偏移量,因此,Solr的不再需要每次從頭開始遍歷結果直到我們想要的記錄,遊標的功能可以大幅提升深翻頁的性能。

用法
遊標的使用非常簡單。在第一個查詢中,我們需要傳遞一個額外的參數- cursorMark = *,告訴Solr返回遊標。在返回中除了搜索結果,我們還可以得到nextCursorMark信息。看看下面這個例子。

查詢

我們從一個簡單的查詢開始:

2
curl ‘localhost:8983/solr/select?q=*:*&rows=1&sort=score+desc,id+asc&cursorMark=*‘

這裏我們傳入一個cursorMark = *參數,告訴Solr的,我們要使用的光標。

搜索結果

上面的查詢將返回以下搜索結果:

<?xml version="1.0" encoding="UTF-8"?>
<response>
 <lst name="responseHeader">
  <int name="status">0</int>
  <int name="QTime">33</int>
  <lst name="params">
   <str name="sort">score desc,id asc</str>
   <str name="start">0</str>
   <str name="q">*:*</str>
   <str name="cursorMark">*</str>
   <str name="rows">1</str>
  </lst>
 </lst>
<result name="response" numFound="32" start="0">
 <doc>
  <str name="id">0579B002</str>
  <str name="name">Canon PIXMA MP500 All-In-One Photo Printer</str>
  <str name="manu">Canon Inc.</str>
  <str name="manu_id_s">canon</str>
  <arr name="cat">
   <str>electronics</str>
   <str>multifunction printer</str>
   <str>printer</str>
   <str>scanner</str>
   <str>copier</str>
  </arr>
  <arr name="features">
   <str>Multifunction ink-jet color photo printer</str>
   <str>Flatbed scanner, optical scan resolution of 1,200 x 2,400 dpi</str>
   <str>2.5" color LCD preview screen</str>
   <str>Duplex Copying</str>
   <str>Printing speed up to 29ppm black, 19ppm color</str>
   <str>Hi-Speed USB</str>
   <str>memory card: CompactFlash, Micro Drive, SmartMedia, Memory Stick, Memory Stick Pro, SD Card, and MultiMediaCard</str>
  </arr>
  <float name="weight">352.0</float>
  <float name="price">179.99</float>
  <str name="price_c">179.99,USD</str>
  <int name="popularity">6</int>
  <bool name="inStock">true</bool>
  <str name="store">45.19214,-93.89941</str>
  <long name="_version_">1461375031699308544</long></doc>
 </result>
 <str name="nextCursorMark">AoIIP4AAACgwNTc5QjAwMg==</str>
</response>

我們看到,除了平時返回的結果外,還多了一個遊標數據nextCursorMark,使用這個值作為我們翻下一頁的參數。

下一個查詢

提交下面這個查詢看一下:

curl ‘localhost:8983/solr/select?q=*:*&rows=1&sort=score+desc,id+asc&cursorMark=AoIIP4AAACgwNTc5QjAwMg==‘

結果如下:

<?xml version="1.0" encoding="UTF-8"?>
<response>
 <lst name="responseHeader">
  <int name="status">0</int>
  <int name="QTime">2</int>
  <lst name="params">
   <str name="sort">score desc,id asc</str>
   <str name="indent">true</str>
   <str name="q">*:*</str>
   <str name="cursorMark">AoIIP4AAACgwNTc5QjAwMg==</str>
   <str name="rows">1</str>
  </lst>
 </lst>
<result name="response" numFound="32" start="0">
 <doc>
  <str name="id">100-435805</str>
  <str name="name">ATI Radeon X1900 XTX 512 MB PCIE Video Card</str>
  <str name="manu">ATI Technologies</str>
  <str name="manu_id_s">ati</str>
  <arr name="cat">
   <str>electronics</str>
   <str>graphics card</str>
  </arr>
  <arr name="features">
   <str>ATI RADEON X1900 GPU/VPU clocked at 650MHz</str>
   <str>512MB GDDR3 SDRAM clocked at 1.55GHz</str>
   <str>PCI Express x16</str>
   <str>dual DVI, HDTV, svideo, composite out</str>
   <str>OpenGL 2.0, DirectX 9.0</str>
  </arr>
  <float name="weight">48.0</float>
  <float name="price">649.99</float>
  <str name="price_c">649.99,USD</str>
  <int name="popularity">7</int>
  <bool name="inStock">false</bool>
  <date name="manufacturedate_dt">2006-02-13T00:00:00Z</date>
  <str name="store">40.7143,-74.006</str>
  <long name="_version_">1461375031846109184</long></doc>
 </result>
 <str name="nextCursorMark">AoIIP4AAACoxMDAtNDM1ODA1</str>
</response>

現在,返回的nextCursorMark變化了,這是新的遊標。

進一步查詢

接下來的查詢就很清楚了,使用cursorMark參數不斷翻頁,再來一次:

curl ‘localhost:8983/solr/select?q=*:*&rows=1&sort=score+desc,id+asc&nextCursorMark=AoIIP4AAACoxMDAtNDM1ODA1‘

總結

Solr的4.7引入的這個遊標參數非常簡單,大大提升了翻頁的效果,詳細的測試報告看這裏:

http://searchhub.org/2013/12/12/coming-soon-to-solr-efficient-cursor-based-iteration-of-large-result-sets

java實現:

  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. }

Solr遊標查詢提高翻頁效率