Cloudant分布式数据库服务在IoT解决方案中的应用

在项目初期,架构往往与快速高效搜索的需求不一致,这导致项目进入重构阶段。在这个阶段,项目团队需要不断与产品负责人讨论重建或重新设计项目以实现更快更高效搜索所需的时间和资源。Cloudant分布式数据库即服务(DBaaS)通过集成Apache Lucene搜索库,帮助解决索引和搜索问题。

Cloudant的NoSQL数据库具有为JSON格式数据特别设计的内置索引,并且索引计算和重新计算算法旨在分布式云环境中高效运行。使用这种功能,不需要编写一行代码或配置。

简而言之,设计文档中定义的搜索索引允许使用Lucene查询解析器语法查询数据库。搜索索引由索引函数定义,类似于MapReduce视图中的map函数。索引函数决定要索引和存储在索引中的数据。

Apache Lucene简介

Apache Lucene是一个开源搜索库,最初由Doug Cutting在1999年发布。2001年,该项目加入了Apache软件基金会Jakarta家族。此后,许多相关项目从Lucene分支出来。目前,这个开源搜索库是最受欢迎的JSON文档处理库。

分布式数据库可以跨多个机架、数据中心甚至不同的云提供商进行扩展。Cloudant中的Apache Lucene实现使得扩展能够带来好处,而不会失去效率和速度。

使用RESTful API或设计文档Web UI,可以定义索引,这些索引会立即构建并准备使用。如前所述,当关键操作发生(如CREATE、UPDATE或DELETE)时,所有索引都会增量更新,包括Lucene索引。

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}); } }

请注意,一些索引声明了参数:

  • "store"设置为true,指示搜索引擎需要保留该值并在请求时返回;
  • "facet"设置为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 Web应用可视化

在这个演示中,将为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请求数据的三个方法中的关键行是指定过滤器的行。

GET面向面的搜索

request.AddQueryParameter("q", "*:*"); request.AddQueryParameter("counts", "[\""+counter+"\""); request.AddQueryParameter("limit", "0");

这种类型的请求发送了三个参数:

  • 主过滤的查询 - 在这种情况下是*:*,因为想要计算所有索引的记录
  • "counts"数组的搜索索引名称 - 在这种情况下,将分别请求"errors"、"city"和"records"
  • "limit"参数限制返回的搜索结果 - 在这种情况下,只需要计数,所以限制是零(不返回记录)

GET地理位置搜索

request.AddQueryParameter("q", "*:*"); request.AddQueryParameter("sort", "\"\""); request.AddQueryParameter("limit", "5");

在这里,请求按距离从给定的纬度和经度排序的前五条记录。

GET文本搜索

request.AddQueryParameter("q", "userMessage:"+ text + "*"); request.AddQueryParameter("limit", "10");

最后一个是简单的搜索,请求的文本用通配符字符扩展,结果限制在10条记录。

Index.html

一个名为Index.html的简单HTML页面(以默认名称命名,以便打开时成为默认页面)加载了jQuery和Google Maps的JavaScript。结果视图显示了面向面的计数和地图上的图钉。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485