所以我有一个应用程序,如果我诚实并不真正需要事务完整性(许多更新,其中没有一个是关键的).因此,我计划暂时将实体组留在路边.但我仍然希望了解它(来自关系背景).
我看到它的方式,我的应用程序的所有查询将基于用户的用户.因此,根据文档建议,我不需要将任何高于用户实体的组分组.但我并没有计划拥有一个特定的用户实体,而是依赖于实体本身的UserProperty.
我看待它的方式,如果我想要事务(基于每个用户),我将需要某种root用户实体作为其数据层次结构的所有实体的父级,无论这个实体有多么薄实际上就是基本上没有属性.
它是否正确?
对于冗长的道歉,我只是真正地指出今晚在实践中实际上意味着什么模式......
我们使用MySQL来存储无模式数据(请参阅:使用关系数据库获取无模式数据,以获得受FriendFeed如何使用MySQL存储无模式数据的解决方案).
一个大表包含我们应用程序的所有实体:
CREATE TABLE entities (
added_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
, id BINARY(16) NOT NULL
, body MEDIUMBLOB
, UNIQUE KEY (id)
) ENGINE=InnoDB ;
Run Code Online (Sandbox Code Playgroud)
一些细节:
存储实体唯一需要的属性是id一个16字节的UUID.实体的其余部分对数据库不透明.我们可以简单地通过在中存储新属性来更改"模式" body.
该added_id列存在,因为InnoDB以主键顺序物理存储数据行.AUTO_INCREMENT主键确保在旧实体之后按顺序在磁盘上写入新实体,这有助于读取/写入位置(新实体比旧实体更频繁地读取).
我们的数据库将我们的无模式数据存储在body.< - 这是这个问题的主题.
许多其他有趣的细节,比如"进入" body数据以构建异步物化视图(索引只是离线构建的表),但它们与当前的讨论无关......
我们应该如何序列化结构化数据(键值对)body?
JSON或BSON很简单,因为每行重复字段名称.这使其具有灵活性的优势,但在空间效率方面也是一个很大的缺点(序列化数据中字段名称的每行开销).我们试图将内容保留在内存中,并且最小化内存和网络占用空间非常重要.我们可以在同一空间中放置的记录越多,查询的速度就越快.我们更喜欢相对较长的描述性字段名称,并缩短它们以使我的数据库更快是错误的!
最后,JSON/BSON对于我们的目的是不可行的,除非我们变得更复杂并将小键映射到与数据库对话的应用程序驱动程序中的更具描述性的键.这让我们思考......
虽然我们的数据库是无模式的,但实际上:1)没有太多不同类型的实体,2)同一类实体的版本不经常更改,3)当它们确实发生变化时,通常只是添加另一个领域.JSON/BSON没有版本控制的原生支持.
在版本控制和数据定义更改方面,Protocol Buffers和Thrift更加复杂.Thrift和Protocol Buffers都是将数据序列化到数据库的理想选择,而Thrift的设计使得编码格式是可扩展的.
协议缓冲区看起来是在无模式数据库中序列化数据的绝佳选择.
CouchDB和MongoDB(两个最流行的无模式数据库?)分别使用JSON和BSON,但我们找不到任何关于使用更高级的东西,比如Protocol Buffers,作为存储无模式数据的序列化格式.有些产品存储特定语言的对象版本(即将Java的Externalizable对象存储在数据网格中,或者在Ruby中使用MySQL进行NoSQL),但这些都很痛苦(尝试从其他平台访问它们,甚至从MySQL本身访问它们,并忘记版本控制).
是否有人在其数据库中存储更具互操作性的协议缓冲区,或在其无模式数据库中存储其他一些高级序列化格式?这是一个问题,除了JSON/BSON/XML的直接每行序列化,还是序列化特定语言的对象之外,是否还有其他选项.它甚至可行吗?我们错过了什么吗?对不起意识风格的叙事流!
我们的REST API允许用户将自定义无模式JSON添加到我们的一些REST资源中,我们需要它可以在Elasticsearch中进行搜索.这种自定义数据及其结构可以在相同类型的资源之间完全不同.
考虑这个示例文档:
{
"givenName": "Joe",
"username": "joe",
"email": "joe@mailinator.com",
"customData": {
"favoriteColor": "red",
"someObject": {
"someKey": "someValue"
}
}
}
Run Code Online (Sandbox Code Playgroud)
除customData遵守架构外的所有字段.customData始终是JSON对象,但该对象中的所有字段和值可能因资源而异.无法保证customData中的任何给定字段名称或值(甚至值类型)在任何两个资源中都是相同的,因为用户可以根据需要编辑这些字段.
支持搜索的最佳方法是什么?
我们认为解决方案是不创建customData索引创建时的任何映射,但随后它变得不可思议(这与ES文档所说的相反).如果对非映射属性的查询起作用,这将是理想的解决方案,并且此方法没有性能问题.但是,在针对该问题运行多个测试之后,我们无法使其工作.
这是需要任何特殊配置的东西吗?或者文档不正确?关于它为什么不起作用的一些澄清将不胜感激.
由于目前这不适合我们,我们已经考虑了几种替代解决方案:
重新索引:这将是昂贵的,因为我们需要重新索引包含该文档的每个索引,并且每次用户使用不同的值类型更新属性时都这样做.性能真的很糟糕,所以这可能不是一个真正的选择.
使用多匹配查询:我们将通过在每次customData对象发生更改时将随机字符串附加到customData字段名称来执行此操作.例如,这就是索引的文档看起来像:
{
"givenName": "Joe",
"username": "joe",
"email": "joe@mailinator.com",
"customData_03ae8b95-2496-4c8d-9330-6d2058b1bbb9": {
"favoriteColor": "red",
"someObject": {
"someKey": "someValue"
}
}
}
Run Code Online (Sandbox Code Playgroud)
这意味着ES将为每个"随机"字段创建一个新映射,我们将在执行查询时使用字段名称的"start with"通配符进行短语多匹配查询.例如:
curl -XPOST 'eshost:9200/test/_search?pretty' -d '
{
"query": {
"multi_match": {
"query" : "red",
"type" : "phrase",
"fields" : ["customData_*.favoriteColor"]
}
}
}' …Run Code Online (Sandbox Code Playgroud)我们有一个应用程序可以处理无模式的财务数据.更准确地说,无data数据是关于订单的信息,其中字段由商家定制.一致性和耐用性很重要.
由于我们的数据报告的动态性非常困难.每条记录可能略有不同,或完全不同.如果我们继续使用关系数据库,我们唯一的选择就是将"文档"序列化为blob.报告必须单独完成,可能是将数据复制到由用户定义的报告定义的公共结构中(每个"报告"都有一个自定义表).
另一种选择是面向文档的NoSQL数据库,如MongoDB.在做了一些研究之后,似乎大多数人都不相信具有财务数据的NoSQL数据库,因为它依赖于BASE而不是ACID.
我似乎发现自己处于两个完全不同的用例中间.我的数据非常适合面向文档的数据库(MongoDB),但我需要ACID数据库的可靠性.同时,复杂的用户定义报告是必需的.
所以我似乎有三个选择:
那三个中的哪一个是我最好的选择(最灵活和最耐用)?是否还有其他选项我没有考虑过我无法改变数据的动态性?有人使用MongoDB进行生产报告吗?
(对于我们的RDMS,我们使用MySQL.考虑切换到MariaDB.选择的编程语言是PHP.考虑使用Sphinx进行全文搜索,比如搜索某人的名字.)
我正在评估一些NoSQL实现(目前是RavenDB和MongoDB),作为一种解决一组特定需求的方法,这些需求涉及无模式数据的存储/检索.我想得到一些关于NoSQL是否应该是我应该查看的方向的反馈,或者是否还有其他(可能更简单的)选项.
基本上我们有一个软件产品(除其他外)定义了一个基本域模型,该模型由几个相关实体组成,每个相关实体都有许多属性(键/值).当我们向客户发布时,我们与他们一起设置属性和值,这实际上是系统的配置.这是相当简单的,因为设计是预先知道的,我们不需要任何动态来实现这一点并使其执行(我们将使用RDBMS).这些属性不是预先知道的,但这也不是问题,因为系统的这一部分几乎围绕属性模型.
问题在于,对于不同的客户,在我们发布并投入生产之后,我们发现我们需要查询特定的属性数据集,这些属性数据在编译和发布代码时(在我们配置属性之前)一无所知顾客).我们基本上需要从我们可以存储的属性映射中生成数据(我们不会预先知道结构),然后以我们无法预料的方式查询存储的数据.现在的想法是我们可以创建在处理期间受到影响的钩子,并允许我们插入库(可能通过MEF)创建数据以便存储,然后在需要时查询它(不用于报告 - 通常用于创建其他数据/属性).
(请注意,创建钩子和插件库是一个单独的问题,并不打算成为此问题的一部分.)
常见的情况可能是:"我想知道过去10天内xxx发生了多少次".所以我会创建一个能够识别xxx已经发生的插件,并将其写入带有日期/时间的数据存储.然后我将创建另一个执行查询的插件(可能在同一个DLL中),并向名为"CountOfxxxInLast10Days"的模型添加一个属性.另一种情况可能是创建可配置的查找.所以我可能有一个在启动时运行的插件来创建/更新可以将一个属性值转换为另一个属性值的查找数据表,或者(更可能)将转换为查找值的一系列值.因此转换插件可能会添加一个包含列的表:bottom_value,top_value,multiplier,查询插件将使用属性值查询表,如"
在某些情况下,旧数据可能会在指定的时间段后被清除.在上述第一种情况中,可能需要从超过十天的商店/缓存中删除数据.
在其他情况下,数据需要永久保留,如上面的第二种情况.这种数据可能只是在启动时重新创建,而不是在永久存储中保存.
其他要求:
我们现在非常致力于.Net平台,因此任何选项都必须拥有可靠的.Net客户端/ API.
如果您使用无模式数据库(特别是面向文档的数据库,如CouchDB,Couchbase,MongoDB)并希望更改特定对象的数据表示格式,则可以保留旧格式的现有记录并以新格式创建新记录.它被宣布为无模式数据库的主要优势之一(我认为因为你可以避免停机).另一方面,处理同类数据的许多格式是不方便和低效的.那么在无模式数据库中将数据从一种格式迁移到另一种格式的好方法/策略是什么?
data-migration document-oriented-db schemaless nosql couchbase
我有一个doc_type,其映射类似于这个非常简化的映射:
{
"test":{
"properties":{
"name":{
"type":"string"
},
"long_searchable_text":{
"type":"string"
},
"clearances":{
"type":"object"
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
该字段clearances应该是一个对象,带有一系列字母数字标识符,用于过滤目的.典型的文档将具有以下格式:
{
"name": "Lord Macbeth",
"long_searchable_text": "Life's but a walking shadow, a poor player, that..."
"clearances": {
"glamis": "aa2862jsgd",
"cawdor": "3463463551"
}
}
Run Code Online (Sandbox Code Playgroud)
问题在于,有时在索引期间,对象字段内的新字段的第一个索引内容clearances将完全是数字的,如上面的情况.这会导致Elasticsearch将此字段的类型推断为long.但这是一个意外.该字段可能是另一个文档中的字母数字.当该字段中包含字母数字值的后一个文档到达时,我得到一个解析异常:
{"error":"MapperParsingException[failed to parse [clearances.cawdor]]; nested: NumberFormatException[For input string: \"af654hgss1\"]; ","status":400}%
Run Code Online (Sandbox Code Playgroud)
我尝试用这样定义的动态模板来解决这个问题:
{
"test":{
"properties":{
"name":{
"type":"string"
},
"long_searchable_text":{
"type":"string"
},
"clearances":{
"type":"object"
}
}
},
"dynamic_templates":[
{
"source_template":{
"match":"clearances.*",
"mapping":{
"type":"string",
"index":"not_analyzed"
}
} …Run Code Online (Sandbox Code Playgroud) 我在无模式模式下使用 Solr 6.1。创建集合并索引示例数据后,创建的字段都设置为 MultiValued = true,唯一的 id 除外。
问题是使用 SolrNet 查询此数据时,它不会将结果正确映射到模型。查询结果作为数组返回,并要求将模型中的所有属性更新为 ICollection 类型。
无论如何,我们可以在索引示例数据时将这些字段设置为 MultiValued = false 吗?
一个例子来说明问题:
1) 在 Schemaless 模式下索引以下模型的样本:
public class TestModel
{
[SolrUniqueKey("id")]
public int Id { get; set; }
[SolrField("guid")]
public Guid Guid { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
2) Solr 的 managed-schema 文件将添加以下字段
<field name="guid" type="strings"/>
<field name="id" type="string" multiValued="false" indexed="true" required="true" stored="true"/>
Run Code Online (Sandbox Code Playgroud)
3) 查询/映射模型时出错
Object of type 'System.Collections.ArrayList' cannot be converted to type
Run Code Online (Sandbox Code Playgroud) 我最近与MongoDB合作并了解了它的无模式设计.但是,我对NoSQL一词感到困惑?为什么叫这个?它不使用SQL或类似SQL的查询吗?
我还从一篇文章中读到,主要区别在于数据的存储方式.这是真的?在MongoDB的情况下,它像JSON文档一样存储.
另外,我很困惑为什么我总是看到'NoSQL vs关系数据库'.NoSQL数据库不是关系型的吗?我相信MongoDB中的文档仍然通过某些键相关/链接(如果我错了,请纠正我).那为什么它被标记为非关系型?
提前致谢!