设为首页 收藏本站
查看: 908|回复: 0

[经验分享] elasticsearch parent-child

[复制链接]

尚未签到

发表于 2017-5-20 11:59:35 | 显示全部楼层 |阅读模式
介绍下ElasticSearch里Parent-Child特性的使用。

//首先创建一系列新闻的索引,这里我们将hot类型作为parent-chid关系里面的parent。

curl -XPUT 'http://localhost:9200/news/hot/1'  -d '{    "uname" : "medcl",    "content" : "河南警方:“南阳老板遭逼供致残与狗同笼”纯属谎言"}'
curl -XPUT 'http://localhost:9200/news/hot/2'  -d '{    "uname" : "medcl",    "content" : "马英九打两岸牌反制绿营"}'
curl -XPUT 'http://localhost:9200/news/hot/3'  -d '{    "uname" : "medcl",    "content" : "专题:中共十七届六中全会公报"}'


//假设我们对每个新闻的评论也分别建立索引,那么新闻的评论和新闻之间会存在一个关系,一篇新闻肯定是存在多个评论,那么我们将评论comment存一个索引,并且和前面的hot新闻索引建立parent-chid关系,评论在这里为child。

//将索引类型hot与comment之间建立parent-child的mapping关系

curl -XPUT 'http://localhost:9200/news/comment/_mapping' -d '{    "comment" : {        "_parent" : {            "type" : "hot"        }    }}'

//直接试试创建一个comment评论看看,发现已经不行了,原来指定了类型拥有parent-child关系之后,必须要带上parent参数

curl -XPUT 'http://localhost:9200/news/comment/1'    -d '
{    "uname" : "凤凰网安徽省六安市网友",    "content" : "河南警方的话没人信"}'
{"error":"RoutingMissingException[routing is required for [news]/[comment]/[1]]"
,"status":500}

正确的方式创建几条评论,并且和前面的第一条新闻建立关系,如下:

curl -XPUT 'http://localhost:9200/news/comment/1?parent=1'    -d '{    "uname" : "凤凰网安徽省六安市网友",    "content" : "河南警方的话没人信"}'
curl -XPUT 'http://localhost:9200/news/comment/2?parent=1'    -d '{    "uname" : "凤凰网湖北省武汉市网友",    "content" : "没有监督权\n没有调查\n一切当然只能是谣言"}'
curl -XPUT 'http://localhost:9200/news/comment/3?parent=1'    -d '{    "uname" : "ladygaga",    "content" : "双下肢不活动,存在废用性肌肉萎缩。请问,这个是怎么做到的?"}'
curl -XPUT 'http://localhost:9200/news/comment/4?parent=1'    -d '{    "uname" : "medcl",    "content" : "额"}'

我们使用has_child查询一下:

curl -XGET 'http://localhost:9200/news/_search' -d '{
    "query" : {
        "has_child" : {
            "type" : "comment",
            "query" :{"term" : {"uname" : "medcl"} }
        }
    }
}'

结果如下:

{
    "took": 10,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "failed": 0
    },
    "hits": {
        "total": 1,
        "max_score": 1,
        "hits": [
            {
                "_index": "news",
                "_type": "hot",
                "_id": "1",
                "_score": 1,
                "_source": {
                    "uname": "medcl",
                    "content": "河南警方:“南阳老板遭逼供致残与狗同笼”纯属谎言"
                }
            }
        ]
    }
}

注意,如果是中文可能需要调整analyzer,默认查询不出来

curl -XGET 'http://localhost:9200/news/_search' -d '{
    "query" : {
        "has_child" : {
            "type" : "comment",
            "query" :{"term" : {"uname" : "凤凰网湖北省武汉市网友"} }
        }
    }
}'

结果:

{
    "took": 0,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "failed": 0
    },
    "hits": {
        "total": 0,
        "max_score": null,
        "hits": []
    }
}

原因分析:
hot类型没有指定使用的分析器,所以中文默认的standard analyzer拆成了一个个的字,但是has_child模式里面的DSL的term query为区配查询,所以查询不出来

curl -XGET 'http://localhost:9200/news/_search' -d '{
    "query" : {
        "has_child" : {
            "type" : "comment",
            "query" :{"term" : {"uname" : "凤"} }
        }
    }
}'

试一下,果然如此,所以mapping的配置还是很重要的。

那怎样解决呢?两种方案
1.给hot类型mapping设置analyzer为not_analyzer(在这里不适用)
2.设置查询时使用的分析器,那就不能使用term query了,term query不支持分析器,我们这里使用可以text query

curl -XGET 'http://localhost:9200/news/_search' -d '{
    "query" : {
        "has_child" : {
            "type" : "comment",
            "query" :{"text" : {"uname" : "凤凰网"} }
        }
    }
}'

当然中文分词用standard analyzer肯定是不行的,你可以灵活替换成其他的中文分析器。
关于text query的其他参数,可以看这里:http://www. elasticsearch .org/guide/reference/query-dsl/text-query.html

ok,我们再试试top_children查询(http://www.elasticsearch.org/guide/reference/query-dsl/top-children-query.html)
topchildren在child进行查询的时候,会预估一个hit size,然后对这个hit size大小的hit结果与parent做查询结果合并聚集,如果合并之后的结果文档数小于查询条件中的from/size参数设置,es则会进行更深度的搜索,这样做的好处是显而易见的,它不会对所有的child索引文档进行处理,可以节省一些额外的开销,但是注意由此造成的total_hits值的不准确。

调用如下:

curl -XGET 'http://localhost:9200/news/_search' -d '{
    "query": {
        "top_children": {
            "type": "comment",
            "query": {
                "text": {
                    "uname": "凤凰网"
                }
            },
            "score": "max",
            "factor": 5,
            "incremental_factor": 2
        }
    }
}'

结果:

{
    "took": 30,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "failed": 0
    },
    "hits": {
        "total": 1,
        "max_score": 0.60276437,
        "hits": [
            {
                "_index": "news",
                "_type": "hot",
                "_id": "1",
                "_score": 0.60276437,
                "_source": {
                    "uname": "medcl",
                    "content": "河南警方:“南阳老板遭逼供致残与狗同笼”纯属谎言"
                }
            }
        ]
    }
}

有了parent-chid这个特性,我们可以做很多事情,比如,如果要给索引数据加上权限,一般来说索引内容本身更新不是很频繁,但是权限信息更新很频繁,我们也可以采用parent-child这种方式来做,如下:

//建立权限子索引

curl -XPUT 'http://localhost:9200/news/role/_mapping' -d '{    "role" : {        "_parent" : {            "type" : "hot"        }    }}'

//创建每个新闻的用户权限索引记录

curl -XPUT 'http://localhost:9200/news/role/1?parent=1'    -d '{    "uid" : "1001"}'
curl -XPUT 'http://localhost:9200/news/role/2?parent=2'    -d '{    "uid" : "1001"}'
curl -XPUT 'http://localhost:9200/news/role/3?parent=3'    -d '{    "uid" : "1003"}'

//执行查询,返回uid为1001可以查看的新闻集合

curl -XGET 'http://localhost:9200/news/_search' -d '{
    "query": {
        "top_children": {
            "type": "role",
            "query": {
                "text": {
                    "uid": "1001"
                }
            },
            "score": "max",
            "factor": 5,
            "incremental_factor": 2
        }
    }
}'

结果:

{
    "took": 10,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "failed": 0
    },
    "hits": {
        "total": 2,
        "max_score": 2.098612,
        "hits": [
            {
                "_index": "news",
                "_type": "role",
                "_id": "1",
                "_score": 2.098612,
                "_source": {
                    "uid": "1001"
                }
            },
            {
                "_index": "news",
                "_type": "role",
                "_id": "2",
                "_score": 1,
                "_source": {
                    "uid": "1001"
                }
            }
        ]
    }
}

//上面通过用户可以直接对parent索引进行数据的过滤,但是往往我们还需要对parent的其他条件进行查询,怎么做呢?
首先ES支持filtered query,对应lucene的filteredquery,主要就是说先查询,得到一个结果集,然后对这个结果集执行filtered查询再过滤一把,es说明在这里(http://www.elasticsearch.org/guide/reference/query-dsl/filtered-query.html)

下面是一些查询的例子,方便参考:

curl -XGET 'http://localhost:9200/news/_search' -d '{
    "query": {
        "filtered": {
            "query": {
                "term": {
                    "content": "河"
                }
            },
            "filter": {
                "or": [
                    {
                        "has_child": {
                            "type": "role",
                            "query": {
                                "term": {
                                    "uid": "1001"
                                }
                            }
                        }
                    },
                    {
                        "has_child": {
                            "type": "comment",
                            "query": {
                                "term": {
                                    "uname": "ladygaga"
                                }
                            }
                        }
                    }
                ]
            }
        }
    }
}'

curl -XGET 'http://localhost:9200/news/_search' -d '{
    "query":

{
    "filtered" : {
        "query" : {
           "top_children": {
                    "type": "role",
                    "query": {
                        "term": {
                            "uid": "1001"
                        }
                    },
                    "score": "max",
                    "factor": 5,
                    "incremental_factor": 2
                }
        },
        "filter" : {
              "fquery" : {
                "query" : {
                    "query_string" : {
                        "query" : "content:马"
                    }
                },
                "_cache" : true
        }
    }
}}}'

curl -XGET 'http://localhost:9200/news/_search' -d '{
    "query":

{
    "filtered" : {
        "query" : {            
                    "query_string" : {
                        "query" : "uname:medcl"
                    }

        },
        "filter" : {
              "has_child": {
                    "type": "role",
                    "query": {
                        "term": {
                            "uid": "1001"
                        }
                    },
                    "score": "max",
                    "factor": 5,
                    "incremental_factor": 2
                }
    }
}}}'

curl -XGET 'http://localhost:9200/news/_search' -d '{
  "query": {
    "bool": {
      "must": [
        {
          "top_children": {
            "type": "role",
            "query": {
              "term": {
                "uid": 1001
              }
            }
          }
        },
        {
          "text": {
            "uname": "medcl"
          }
        }
      ]
    }
  }
}'

curl -XGET 'http://localhost:9200/news/_search' -d '{
  "query": {
    "bool": {
      "must": [
        {
          "top_children": {
            "type": "role",
            "query": {
              "term": {
                "uid": 1001
              }
            }
          }
        },
        {
          "text": {
            "content": "马英九"
          }
        }
      ]
    }
  }
}'

需要注意的是,parent-chid这种特性虽好,但是也要用对地方,服务端会将所有的_id加载到内存中进行关联和过滤,所以必须保证内存足够大才行。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-379323-1-1.html 上篇帖子: elasticsearch java api——客户端 org.elasticsearch.client 下篇帖子: elasticsearch-curator的安装
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表