使用Couchbase分页

如果对Couchbase集群进行查询时必须处理大量文档,则使用分页来逐页获取行很重要。 您可以在“ 分页 ”一章的文档中找到一些信息,但是我想在本文中提供更多详细信息和示例代码。

在此示例中,我将基于啤酒样本数据集创建一个简单的视图,该视图用于按国家/地区查找啤酒厂:

function (doc, meta) {
  if (doc.type == "brewery" && doc.country){
   emit(doc.country);
  } 
}

该视图按国家列出所有啤酒厂,索引如下:

文件编号
狂暴者 阿根廷 空值
cervecera_jerome 阿根廷 空值
brouwerij_nacional_balashi 阿鲁巴岛 空值
australian_brewing_corporation 澳大利亚 空值
carlton_and_united_breweries 澳大利亚 空值
库珀酿酒厂 澳大利亚 空值
寄养人_s_澳大利亚_公司 澳大利亚 空值
gold_coast_brewery 澳大利亚 空值
lion_nathan_australia_hunter_street 澳大利亚 空值
little_creatures_brewery 澳大利亚 空值
麦芽铲子酿酒厂 澳大利亚 空值
matilda_bay_brewing 澳大利亚 空值
yellowstone_valley_brewing 美国 空值
yuengling_son_brewing 美国 空值
zea_rotisserie_and_brewery 美国 空值
培养者 越南 空值
色相酿酒 越南 空值

因此,现在您要以5行的页面大小浏览此索引。

使用跳过/限制参数

最简单的方法是使用limit和skip参数,例如:

页面1:?limit = 5&skip0

页面2:?limit = 5&skip = 5

页面x:?limit = 5&skip(limit *(page-1))

很明显,您可以使用进行范围或键查询(startkey / endkey,键,键)和排序选项(降序)所需的任何其他参数。

这是简单但不是最有效的方法,因为查询引擎必须读取与查询匹配的所有行,直到达到跳过值。

python中的一些代码示例使用此视图进行分页:

from couchbase import Couchbase
cb = Couchbase.connect(bucket='beer-sample')

hasRow = True
rowPerPage = 5
page = 0
currentStartkey=""
startDocId=""

while hasRow :
  hasRow = False
	skip = 0 if page == 0 else 1
	page = page + 1
	print "-- Page %s --" % (page)
	rows = cb.query("test", "by_country", limit=rowPerPage, skip=skip, startkey=currentStartkey, startkey_docid=startDocId)
	for row in rows:
		hasRow = True
		print "Country: \"%s\" \t Id: '%s'" % (row.key, row.docid)
		currentStartkey = row.key
		startDocId = row.docid
	print " -- -- -- -- \n"

该应用程序在所有页面上循环,直到索引结束。

正如我之前所说,这不是最佳方法,因为系统必须读取所有值,直到达到跳过为止。 以下示例显示了解决此问题的更好方法。

使用startkey / startkey_docid参数

为了使这种分页更加有效,可以采用另一种方法。 此方法使用startkey和startkey_docid选择适当的文档。

  • startkey参数将是查询应开始读取的键的值(基于“上一页”的最后一个键)
  • 由于对于例如“ Germany”的键,您可能具有一个或多个ID(文档),因此有必要对Couchbase查询引擎说从哪里开始,为此,您需要使用startkey_docid参数,并忽略此ID,因为它是前一页的最后一个。

因此,如果我们查看索引,并添加一个行号来说明分页

行数 文件编号
查询第1页
极限= 5
1个 狂暴者 阿根廷 空值
2 cervecera_jerome 阿根廷 空值
3 brouwerij_nacional_balashi 阿鲁巴岛 空值
4 australian_brewing_corporation 澳大利亚 空值
5 carlton_and_united_breweries 澳大利亚 空值
查询第2页
?limit = 5&startkey =“澳大利亚”&startkey_docid = carlton_and_united_breweries&skip = 1
6 库珀酿酒厂 澳大利亚 空值
7 寄养人_s_澳大利亚_公司 澳大利亚 空值
8 gold_coast_brewery 澳大利亚 空值
9 lion_nathan_australia_hunter_street 澳大利亚 空值
10 little_creatures_brewery 澳大利亚 空值
查询第3页
?limit = 5&startkey =“澳大利亚”&startkey_docid = little_creatures_brewery&skip = 1
11 麦芽铲子酿酒厂 澳大利亚 空值
12 matilda_bay_brewing 澳大利亚 空值
yellowstone_valley_brewing 美国 空值
yuengling_son_brewing 美国 空值
zea_rotisserie_and_brewery 美国 空值
培养者 越南 空值
色相酿酒 越南 空值

因此,如您在上面的示例中看到的那样,查询使用startkey和文档ID,并使用skip = 1传递它。

现在,让我们再次使用Python查看应用程序代码

from couchbase import Couchbase
cb = Couchbase.connect(bucket='beer-sample')

hasRow = True
rowPerPage = 5
page = 0
currentStartkey=""
startDocId=""

while hasRow :
	hasRow = False
	skip = 0 if page == 0 else 1
	page = page + 1
	print "-- Page %s --" % (page)
	rows = cb.query("test", "by_country", limit=rowPerPage, skip=skip, startkey=currentStartkey, startkey_docid=startDocId)
	for row in rows:
		hasRow = True
		print "Country: \"%s\" \t Id: '%s'" % (row.key, row.docid)
		currentStartkey = row.key
		startDocId = row.docid
	print " -- -- -- -- \n"

该应用程序在所有页面上循环,直到索引结束

使用这种方法,应用程序开始在特定键(startkey参数)处读取索引,并且仅在索引中的必要条目上循环。 这比使用简单的跳过方法更有效。

具有减少功能的视图

当您的视图使用reduce函数进行分组时,无法使用参数startkey_docid,因为在缩小结果时文档的ID不可用。

因此,在使用reduce时,必须使用skip和limit参数。

Couchbase Java SDK分页器

在前面的示例中,我展示了如何使用各种查询参数进行分页。 Java SDK提供了一个Paginator对象,以帮助开发人员处理分页。 以下示例在Paginator API中使用相同的视图。

package com.couchbase.devday;

import com.couchbase.client.CouchbaseClient;
import com.couchbase.client.protocol.views.*;
import java.net.URI;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;

public class JavaPaginatorSample {

public static void main(String[] args) {

	configure();
	System.out.println("--------------------------------------------------------------------------");
	System.out.println("\tCouchbase - Paginator");
	System.out.println("--------------------------------------------------------------------------");

    List<URI> uris = new LinkedList<URI>();
    uris.add(URI.create("http://127.0.0.1:8091/pools"));

    CouchbaseClient cb = null;
    try {
    	cb = new CouchbaseClient(uris, "beer-sample", "");
	  	System.out.println("--------------------------------------------------------------------------");
	  	System.out.println("Breweries (by_name) with docs & JSON parsing");
		View view = cb.getView("test", "by_country");
		Query query = new Query();
		int docsPerPage = 5;

		Paginator paginatedQuery = cb.paginatedQuery(view, query, docsPerPage);
		int pageCount = 0;
		while(paginatedQuery.hasNext()) {
			pageCount++;
			System.out.println(" -- Page "+ pageCount +" -- ");
			ViewResponse response = paginatedQuery.next();
			for (ViewRow row : response) {
				System.out.println(row.getKey() + " : " + row.getId());
			}
			System.out.println(" -- -- -- ");
		}
		
		System.out.println("\n\n");
    	cb.shutdown(10, TimeUnit.SECONDS);
    } catch (Exception e) {
    	System.err.println("Error connecting to Couchbase: " + e.getMessage());
    }
}



private static void configure() {

	for(Handler h : Logger.getLogger("com.couchbase.client").getParent().getHandlers()) {
		if(h instanceof ConsoleHandler) {
			h.setLevel(Level.OFF);
		}
	}
	Properties systemProperties = System.getProperties();
	systemProperties.put("net.spy.log.LoggerImpl", "net.spy.memcached.compat.log.SunLogger");
	System.setProperties(systemProperties);

	Logger logger = Logger.getLogger("com.couchbase.client");
	logger.setLevel(Level.OFF);
	for(Handler h : logger.getParent().getHandlers()) {
		if(h instanceof ConsoleHandler){
			h.setLevel(Level.OFF);
		}
	}
}

}

如您所见,您可以使用Java Paginator轻松对查询结果进行分页。

  • 在第37行,使用视图和查询对象创建Paginator,并指定页面大小
  • 然后,您只需要使用hasNext()和next()方法来导航结果。

Java Paginator知道他们的查询使用的是减少还是不使用,因此您可以将其与所有类型的查询一起使用–在内部,它将在跳过/限制方法和doc_id方法之间切换。 您可以在Paginator类中看到它是如何完成的

请注意,如果要在HTTP请求之间的Web应用程序中执行此操作,则必须将Paginator对象保留在用户会话中,因为当前API会将当前页面保持在其状态。

结论

在此博客文章中,您学习了如何在Couchbase视图中处理分页。 总结

  • 分页基于您在执行查询时发送的某些特定参数。
  • Java开发人员可以使用简化分页的Paginator类。

我邀请您查看仍在开发中的新Couchbase查询语言N1QL,它将使用LIMIT&OFFSET参数为开发人员提供更多选项,包括分页,例如:

SELECT fname, age 
    FROM tutorial
        WHERE age > 30
    LIMIT 2
    OFFSET 2

如果您想了解有关N1QL的更多信息:

参考:来自Tug博客博客的JCG合作伙伴 Tugdual Grall 使用Couchbase进行分页

翻译自: https://www.javacodegeeks.com/2013/10/pagination-with-couchbase.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值