ES原生支持Object类型,也就是任意字段都可以是个对象,而ES又是所有字段都支持多值,即都可以是list。es的object类型虽然是对象类型,但是数据是打平存储的。
如下,声明一个对象,新增1条数据:
DELETE /test-index
PUT /test-index
{
"settings": {
"number_of_shards": 8,
"number_of_replicas": 1,
"codec": "best_compression"
},
"mappings": {
"test-type": {
"dynamic": "true",
"_routing": {
"required": false
},
"_all": {
"enabled": false
},
"properties": {
"keywordsWithCount": {
"dynamic": "false",
"properties": {
"keyword": {
"type": "keyword"
},
"count": {
"type": "keyword"
}
}
},
"companyName": {
"type": "keyword"
}
}
}
}
}
POST /test-index/test-type/1
{
"companyName": "大富翁",
"keywordsWithCount": [
{
"keyword": "NP0001",
"count": "5"
},
{
"keyword": "NP0002",
"count": "15"
}
]
}
GET /test-index/_search
但实际存储的时候,是打平这样存储的:
{
"companyName" : "大富翁",
"keywordsWithCount.keyword": ["NP0001", "NP0002"],
"keywordsWithCount.count": ["1", "2"]
}
就丢失了keyword和count之间的关联关系,就不知道谁是 1谁是2了。所以,这样查询也能查询出结果:
GET /test-index/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"keywordsWithCount.keyword": "NP0001"
}
},
{
"term": {
"keywordsWithCount.count": "2"
}
}
]
}
}
}
返参:
"hits" : [
{
"_index" : "test-index",
"_type" : "test-type",
"_id" : "1",
"_source" : {
"companyName" : "大富翁",
"keywordsWithCount" : [
{
"keyword" : "NP0001",
"count" : "1"
},
{
"keyword" : "NP0002",
"count" : "2"
}
]
}
}
]
可是NP0001是1,NP0002才是2 所以,为解决es object类型的数据扁平化存储问题,引入了nested类型。
nested类型:嵌套文档,对象数组的优先选择类型。Nested将数组中的每个对象作为单独的隐藏文档(hidden separate document)进行索引。
解决问题:对象数组的多字段匹配查询。
在独立索引每一个嵌套对象后,对象中每个字段的相关性得以保留。我们查询时,也仅仅返回那些真正符合条件的文档。
不仅如此,由于嵌套文档直接存储在文档内部,查询时嵌套文档和根文档联合成本很低,速度和单独存储几乎一样。
嵌套文档是隐藏存储的,我们不能直接获取。如果要增删改一个嵌套对象,我们必须把整个文档重新索引才可以。值得注意的是,查询的时候返回的是整个文档,而不是嵌套文档本身。
如果需要索引对象数组而不是单个对象,优先考虑使用嵌套数据类型Nested。
如果不需要对 Nested 子文档精确搜索的就选型 object,需要的选型 Nested。
nested类型的定义在声明时指定 "type": "nested" 即可!
DELETE /test-index-2
PUT test-index-2
{
"settings": {
"number_of_shards": 8,
"number_of_replicas": 1,
"codec": "best_compression"
},
"mappings": {
"test-type": {
"dynamic": "true",
"_routing": {
"required": false
},
"_all": {
"enabled": false
},
"properties": {
"keywordsWithCount": {
"type": "nested",
"dynamic": "false",
"properties": {
"keyword": {
"type": "keyword"
},
"count": {
"type": "keyword"
}
}
},
"companyName": {
"type": "keyword"
}
}
}
}
}
POST /test-index-2/test-type/1
{
"companyName": "大富翁",
"keywordsWithCount": [
{
"keyword": "NP0001",
"count": "5"
},
{
"keyword": "NP0002",
"count": "15"
}
]
}
GET /test-index-2/_search
Nested因为是单独的子文档存储,因此在使用时,直接用 a.b.c 是无法访问的,需要将其套在nested查询里,且需要指定 "path" 。
GET /test-index-2/_search
{
"query": {
"nested": {
"path": "keywordsWithCount",
"query": {
"bool": {
"must": [
{
"term": {
"keywordsWithCount.keyword": "NP0001"
}
},
{
"term": {
"keywordsWithCount.count": "2"
}
}
]
}
}
}
}
}
这时返回的数据为空,满足我们的需求。
Nested注意点:
由于单独存储很耗资源,因此默认一个index最多只有50个nested字段。此外,虽然nested是单独存储的,但是其字段数也算入index总字段数,默认最多1000个。
Nested结构是个List结构。Nested Aggregation就是对这个list做agg操作,agg写法和普通的一样,只需要在外面套上nested即可。
能否用Nested做动态kv?
Nested除了存储固定的Object List,还有一种常用的场景就是用来存储动态的KV。虽然ES天然支持dynamic mapping,但是其key都是固化在每一个doc中的,如果存储用户自定义报表数据。每个用户的key差异很大,放在同一张表会出现大量空值。这是很浪费系统资源的行为,并且随着Key的不断增多,最终会超出index的最大key数量。
因此用nested结构来处理这种动态kv就比较合适。 nested的本质就是将
{"tags":{"k1":"v1","k2":"v2"}}
=>
{"tags":[{"key":"key1","value":"v1"},{"key":"key2","value":"v2"}]}
这样一来就可以轻松处理动态kv。并且查询依旧简单,例如k1:v1 AND k2:v2变为
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "tags",
"query": {
"query_string": {
"query": "tags.key:k1 AND tags.value:v1"
}
}
}
},
{
"nested": {
"path": "tags",
"query": {
"query_string": {
"query": "tags.key:k2 AND tags.value:v2"
}
}
}
}
]
}
}
}
Nested 新增或更新子文档操作,为什么需要更新整个文档?
嵌套 Nested 文档在物理上位于根文档旁边的 Lucene 段中。这是为什么当只想更改单个嵌套文档时必须重建根文档和所有嵌套 Nested 文档的原因。
参考文档:
https://www.elastic.co/guide/cn/elasticsearch/guide/current/nested-objects.html
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
当我使用Bundler时,是否需要在我的Gemfile中将其列为依赖项?毕竟,我的代码中有些地方需要它。例如,当我进行Bundler设置时:require"bundler/setup" 最佳答案 没有。您可以尝试,但首先您必须用鞋带将自己抬离地面。 关于ruby-我需要将Bundler本身添加到Gemfile中吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/4758609/
在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev
我有一个ModularSinatra应用程序,我正在尝试将Bootstrap添加到应用程序中。get'/bootstrap/application.css'doless:"bootstrap/bootstrap"end我在views/bootstrap中有所有less文件,包括bootstrap.less。我收到这个错误:Less::ParseErrorat/bootstrap/application.css'reset.less'wasn'tfound.Bootstrap.less的第一行是://CSSReset@import"reset.less";我尝试了所有不同的路径格式,但它
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象