在项目初期,架构往往与快速高效搜索的需求不一致,这导致项目进入重构阶段。在这个阶段,项目团队需要不断与产品负责人讨论重建或重新设计项目以实现更快更高效搜索所需的时间和资源。Cloudant分布式数据库即服务(DBaaS)通过集成Apache Lucene搜索库,帮助解决索引和搜索问题。
Cloudant的NoSQL数据库具有为JSON格式数据特别设计的内置索引,并且索引计算和重新计算算法旨在分布式云环境中高效运行。使用这种功能,不需要编写一行代码或配置。
简而言之,设计文档中定义的搜索索引允许使用Lucene查询解析器语法查询数据库。搜索索引由索引函数定义,类似于MapReduce视图中的map函数。索引函数决定要索引和存储在索引中的数据。
Apache Lucene是一个开源搜索库,最初由Doug Cutting在1999年发布。2001年,该项目加入了Apache软件基金会Jakarta家族。此后,许多相关项目从Lucene分支出来。目前,这个开源搜索库是最受欢迎的JSON文档处理库。
分布式数据库可以跨多个机架、数据中心甚至不同的云提供商进行扩展。Cloudant中的Apache Lucene实现使得扩展能够带来好处,而不会失去效率和速度。
使用RESTful API或设计文档Web UI,可以定义索引,这些索引会立即构建并准备使用。如前所述,当关键操作发生(如CREATE、UPDATE或DELETE)时,所有索引都会增量更新,包括Lucene索引。
索引的定义方式和查询语法的组合允许对数据库中的任何JSON字段执行数值、日期、文本、布尔和地理空间查询。以下是搜索语法的一些功能:
将重用之前文章中代码结构,扩展发送到Cloudant DBaaS的JSON内容。增强的传感器将像以前一样发送温度和湿度,但现在它们将包括设备ID、地理位置、用户消息和错误消息。数据将直接流入Cloudant。
这不是IoT解决方案的常见架构设计,因为架构师更喜欢设计中间服务以提供安全性和版本控制。使用Cloudant,可以直接从设备到数据库发送数据,使用Cloudant DBaaS提供的API密钥级别的安全性。由于数据库不是关系型的,可以将不同的JSON版本集成到同一个数据库中,由相同(或版本升级)的索引处理。
因此,Sensor类看起来像这样:
public class Sensor {
public string _id;
public string recordtitle;
public string record;
public string origtime;
public int displacement;
public int temp;
public int hmdt;
public long modified;
public string tags;
public string city;
public double lat;
public double lon;
public string deviceId;
public string userMessage;
public string errorMessage;
}
传感器数据生成方法有多个预定义的设备ID、城市和地理位置组合,以及几个错误消息和用户消息。
多参数索引
使用设计文档UI,将为六个查询的字段创建一个新的搜索索引。这个搜索索引将六个搜索索引组合在一起,允许执行复杂的查询,请求与这些字段相关的记录。例如:
以下代码为关键属性生成命名索引:
function (doc) {
index("deviceId", doc.deviceId);
if (doc.origtime) {
index("time", doc.origtime, {"store": true});
}
if (doc.lat && doc.lon) {
index("lat", doc.lat, {"store": true});
index("lon", doc.lon, {"store": true});
index("city", doc.city, {"store": true});
}
if (doc.userMessage && doc.userMessage.length !== 0) {
index("userMessage", doc.userMessage, {"store": true});
}
}
请注意,一些索引声明了参数:
生成的搜索索引可以从UI中测试。
为了便于REST访问,将为面向面的索引创建三个单独的搜索索引。在那里访问的字段是城市、传感器记录名称和错误消息(因为错误消息是有限范围的错误代码)。
最后,将有这种类型的设计文档:
facetErrors
function (doc) {
if (doc.errorMessage && doc.errorMessage.length !== 0) {
index("errors", doc.errorMessage, {"facet": true});
}
}
facetCity
function (doc) {
if (doc.city) {
index("city", doc.city, {"store": true, "facet": true});
}
}
facetRecords
function (doc) {
if (doc.recordtitle) {
index("record", doc.recordtitle, {"store": true, "facet": true});
}
}
在这个演示中,将为Azure Cloud Web Site构建最简单的解决方案。这就是为什么从一个空模板开始。
对web.config进行几次更改 - 添加应用程序设置并启用默认文档:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="username" value="[username]"/>
<add key="password" value="[password]"/>
</appSettings>
...
<system.webServer>
<defaultDocument enabled="true"/>
...
</system.webServer>
</configuration>
安装一个nuget库(需要对Cloudant DB进行REST API调用)
添加一个静态帮助类来处理Cloudant搜索索引 - 在GitHub上查看代码。从Cloudant请求数据的三个方法中的关键行是指定过滤器的行。
request.AddQueryParameter("q", "*:*");
request.AddQueryParameter("counts", "[\""+counter+"\"");
request.AddQueryParameter("limit", "0");
这种类型的请求发送了三个参数:
request.AddQueryParameter("q", "*:*");
request.AddQueryParameter("sort", "\"\"");
request.AddQueryParameter("limit", "5");
在这里,请求按距离从给定的纬度和经度排序的前五条记录。
request.AddQueryParameter("q", "userMessage:"+ text + "*");
request.AddQueryParameter("limit", "10");
最后一个是简单的搜索,请求的文本用通配符字符扩展,结果限制在10条记录。
一个名为Index.html的简单HTML页面(以默认名称命名,以便打开时成为默认页面)加载了jQuery和Google Maps的JavaScript。结果视图显示了面向面的计数和地图上的图钉。