此功能已经存在了一段时间,但仍值得一提。一些Key-Value Store只允许你将整个文档全部整合在一起,这是一个合理的。但是,如果你使用Couchbase作为KV,仍然可以通过指定文档的路径来操作文档的各个部分。例如以下文件:
{
"name": "Douglas Reynholm",
"email": "douglas@reynholmindustries.com",
"addresses": {
"billing": {
"line1": "123 Any Street",
"line2": "Anytown",
"country": "United Kingdom"
},
"delivery": {
"line1": "123 Any Street",
"line2": "Anytown",
"country": "United Kingdom"
}
},
"purchases": {
"complete": [
339, 976, 442, 666
],
"abandoned": [
157, 42, 999
]
}
}
你可以通过简单地指定文档的路径来操作文档的各个部分,如GET('addresses.billing')或ARRAY_APPEND('purchases.abandoned',42)
如果你想了解更多信息,请查看我们的官方文档。
事件显然是Couchbase 5.5中最酷的功能之一。Eventing Service使你能够编写服务器端功能,每当插入/更新/删除文档时,这些功能都会自动触发。可以使用类似JavaScript的语法轻松编写这些函数:
此外,还可以通过curl调用应用程序中的端点:
function OnUpdate(doc, meta) {
if (doc.resourceType != 'Observation') return;
let reference = doc.subject.reference;
let url = "http://localhost:8080/events/" + reference.substr(9);
let data = JSON.stringify({
"reference": doc.subject.reference,
"code": doc.code.coding[0].code,
"recordedAt": doc.issued,
"value": doc.valueQuantity.value
});
let curl = SELECT CURL($url, {
"request": "POST",
"header": [ "Content-Type: application/json", "accept: application/json" ],
"data": $data
});
curl.execQuery();
}
function OnDelete(meta) {}
Couchbase允许你在查询中长时间的使用joins,但到目前为止,它只能通过使用我们自己的语法来完成。从Couchbase 5.5开始,你还可以使用ANSI JOIN语法:
SELECT DISTINCT route.destinationairport
FROM `travel-sample` airport JOIN `travel-sample` route
ON airport.faa = route.sourceairport
AND route.type = "route"
WHERE airport.type = "airport"
AND airport.city = "San Francisco"
AND airport.country = "United States";
大多数面向用户的应用程序最终需要实现某种高级搜索。这种特性通常要求你将数据推送到第三方工具,如Solr或ElasticSearch。但是,添加此类工具会显著增加基础结构的成本和复杂性,更不用说将对象/文档更改推送到这些工具所需的所有代码。
从Couchbase 5.0开始,你可以在web控制台中创建全文搜索索引,然后直接从数据库进行全文搜索:
突出显示搜索结果:
如何通过SDK进行简单搜索:
@Override
public List<SearchQueryRow> searchQuery(String word) {
String indexName = "movies_index";
QueryStringQuery query = SearchQuery.queryString(word);
SearchQueryResult result = movieRepository.getCouchbaseOperations().getCouchbaseBucket().query(
new SearchQuery(indexName, query).highlight().limit(20));
List<SearchQueryRow> hits = new ArrayList<>();
if (result != null && result.errors().isEmpty()) {
Iterator<SearchQueryRow> resultIterator = result.iterator();
while (resultIterator.hasNext()) {
hits.add(resultIterator.next());
}
}
return hits;
}
5)更快的查询、GROUP BYs和聚合下推
无论数据库如何,聚合(min、max、avg等)和GROUP Bys操作在性能方面一直存在问题。为了解决这个问题,使用Couchbase 5.5,你可以利用你的索引来加速这些类型的查询:
SELECT country, state, city, COUNT(1) AS total
FROM `travel-sample`
WHERE type = 'hotel' and country is not null
GROUP BY country, state, city
ORDER BY COUNT(1) DESC;
~90 MS-上述查询的查询计划
~7ms-与之前相同的查询,但使用适当的索引
数据库是任何恶意入侵者的头奖,这就是为什么添加额外的安全层永远不会太多的原因。使用Couchbase,您可以使用X.509证书对客户端进行身份验证,并通过基于角色的访问控制(RBAC)限制其访问:
你还可以通过N1QL授予权限:
GRANT ROLE query_select(some_bucket) TO denis;
静态加密是最基本的安全形式之一,你可以使用Couchbase的Java加密轻松加密/解密字段:
public static class Person {
@Id
public String id;
@EncryptedField(provider = "AES")
public String password;
//The rest will be transported and stored unencrypted
public String firstName;
public String lastName;
public String userName;
public int age;
}
在Couchbase,我们试图授权开发人员微调他们的性能,即使是在文档级别,因此开发人员可以根据具体情况决定每种方案的最佳权衡。
让我们来看看Couchbase如何存储数据。默认情况下,只要服务器确认应存储新文档,它就会将响应发送回客户端,说明你的“请求已成功接收”并且异步地存储并复制文档。
这种方法非常好,但如果服务器在文档仍在服务器内存时崩溃,则丢失数据的可能性很小。如果你想避免这种情况,你可以通过SDK指定只有在文档被复制或存储在磁盘中后才能收到确认:
movieRepository.getCouchbaseOperations().save(movie, PersistTo.ONE, ReplicateTo.NONE);
//or
movieRepository.getCouchbaseOperations().save(movie, PersistTo.ONE, ReplicateTo.TWO);
...
movieRepository.getCouchbaseOperations().save(movie, PersistTo.NONE, ReplicateTo.ONE);
为什么要允许这样的事情发生?
因为如果服务器崩溃,而你不能承受丢失这些数据,那么你需要大大提高你的性能。你可以决定系统的哪些部分值得冒这样的风险。
你也可以对查询执行类似操作。在这种情况下,你可以根据上次更改等待索引/视图更新,或者你可以决定是否返回最新版本的文档:
//You can use ScanConsistency.REQUEST_PLUS, ScanConsistency.NOT_BOUNDED or ScanConsistency.STATEMENT_PLUS
N1qlParams params = N1qlParams.build().consistency(ScanConsistency.REQUEST_PLUS).adhoc(true);
ParameterizedN1qlQuery query = N1qlQuery.parameterized(queryString, JsonObject.create(), params);
resourceRepository.getCouchbaseOperations().getCouchbaseBucket().query(query);
我们的SDK中还有一些其他特性也可以进行优化,所有这些小决策都可以显著提高你的性能。
自5.5版以来,我们引入了一种新的功能,称为响应时间可观测性,它将为系统开发人员提供一种非常简单的方法来观察相对于可调阈值的响应时间。
这个特性使用OpenTracking格式,记录慢速请求,并在每次间隔之后记录有关它的详细信息,以便你可以轻松识别性能较差的操作。
Apr 04, 2018 9:42:57 AM com.couchbase.client.core.tracing.ThresholdLogReporter logOverThreshold
WARNING: Operations over threshold: [ {
"top" : [ {
"server_us" : 8,
"local_id" : "41837B87B9B1C5D1/000000004746B9AA",
"local_address" : "127.0.0.1:55011",
"operation_id" : "get:0x6",
"dispatch_us" : 315,
"remote_address" : "127.0.0.1:11210",
"total_us" : 576
}, {
"server_us" : 8,
"local_id" : "41837B87B9B1C5D1/000000004746B9AA",
"local_address" : "127.0.0.1:55011",
"operation_id" : "get:0x5",
"dispatch_us" : 319,
"remote_address" : "127.0.0.1:11210",
"total_us" : 599
}, {
"server_us" : 8,
"local_id" : "41837B87B9B1C5D1/000000004746B9AA",
"local_address" : "127.0.0.1:55011",
"operation_id" : "get:0x4",
"dispatch_us" : 332,
"remote_address" : "127.0.0.1:11210",
"total_us" : 632
}, {
"server_us" : 11,
"local_id" : "41837B87B9B1C5D1/000000004746B9AA",
"local_address" : "127.0.0.1:55011",
"operation_id" : "get:0x3",
"dispatch_us" : 392,
"remote_address" : "127.0.0.1:11210",
"total_us" : 762
}, {
"server_us" : 23,
"local_id" : "41837B87B9B1C5D1/000000004746B9AA",
"local_address" : "127.0.0.1:55011",
"operation_id" : "get:0x1",
"decode_us" : 9579,
"dispatch_us" : 947,
"remote_address" : "127.0.0.1:11210",
"total_us" : 16533
}, {
"server_us" : 56,
"encode_us" : 12296,
"local_id" : "41837B87B9B1C5D1/000000004746B9AA",
"local_address" : "127.0.0.1:55011",
"operation_id" : "upsert:0x2",
"dispatch_us" : 1280,
"remote_address" : "127.0.0.1:11210",
"total_us" : 20935
} ],
"service" : "kv",
"count" : 6
} ]
默认情况下,响应时间可观察性处于启用状态,我们已经定义了一组阈值以避免记录请求。如果要突破群集的限制,甚至可以手动设置较小的阈值。
原文标题《10 Things That Developers Must Know About Couchbase》
作者:Denis W S Rosa
译者:lemon
不代表云加社区观点,更多详情请查看原文链接
本文系外文翻译,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系外文翻译,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。