内容简介:我们在使用Elasticsearch做搜索引擎的时候有可能会遇到跨domain查询的场景,比如做一个学生课程管理系统,搜一个学生的名字,像知道该学生的选课情况。当然解决问题的方法有很多,我可以搜学生,然后去db查找学生关联的选课,就可以查到所有的课程,有时候数据量不是很大,并且我的索引只有一个课程维度的时候,就需要使用嵌套类型来解决这类问题。本文使用es和kibina来操作实例,因为基于中文的实例,还使用到了ik分词器,具体可以参考:
1.背景介绍
我们在使用Elasticsearch做搜索引擎的时候有可能会遇到跨domain查询的场景,比如做一个学生课程管理系统,搜一个学生的名字,像知道该学生的选课情况。
当然解决问题的方法有很多,我可以搜学生,然后去db查找学生关联的选课,就可以查到所有的课程,有时候数据量不是很大,并且我的索引只有一个课程维度的时候,就需要使用嵌套类型来解决这类问题。本文使用es和kibina来操作实例,因为基于中文的实例,还使用到了ik分词器,具体可以参考:
2.对象类型
Elasticsearch支持对象类型的存储,我们可以把一个对象数组存到某个document的字段内,比如一个课程作为一个document,那么这个课程可以建立一个students字段,存储该课程下的学生object数组。
在Elasticsearch中,新建一个如下的class_test索引,其中student作为一个object数组类型。
PUT /class_test { "mappings":{ "class_test": { "properties": { "id": { "type": "keyword" }, "name": { "analyzer": "ik_max_word", "type": "text" }, "type":{ "type":"keyword" }, "student":{ "properties": { "name":{ "analyzer": "ik_max_word", "type": "text" }, "id":{ "type":"keyword" } } } } } }, "settings":{ "index": { "refresh_interval": "1s", "number_of_shards": 5, "max_result_window": "10000000", "mapper": { "dynamic": "false" }, "number_of_replicas": 0 } } }复制代码
往class_test放入一下数据,现在索引里面一共有两条数据
{ "took" : 1, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 2, "max_score" : 1.0, "hits" : [ { "_index" : "class_test", "_type" : "class_test", "_id" : "ijfJ5GoBJeNZPNCWykLR", "_score" : 1.0, "_source" : { "id" : "1", "name" : "数学课", "student" : [ { "id" : "1", "name" : "张三" }, { "id" : "2", "name" : "李四" } ] } }, { "_index" : "class_test", "_type" : "class_test", "_id" : "Q9NxGGsBa-TqHCWqAaM4", "_score" : 1.0, "_source" : { "id" : "2", "name" : "语文", "student" : [ { "id" : "3", "name" : "杰克" }, { "id" : "4", "name" : "玛丽" } ] } } ] } }复制代码
接下来,我们可以使用查询语句对索引进行查询。当我们查询id为1的学生参见的课程的时候,可以查到数学课。
GET /class_test/class_test/_search { "query": { "bool": { "must": [ { "match": { "student.id": "1" } } ] } } }复制代码
{ "took" : 0, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 1, "max_score" : 0.2876821, "hits" : [ { "_index" : "class_test", "_type" : "class_test", "_id" : "ijfJ5GoBJeNZPNCWykLR", "_score" : 0.2876821, "_source" : { "id" : "1", "name" : "数学课", "student" : [ { "id" : "1", "name" : "张三" }, { "id" : "2", "name" : "李四" } ] } } ] } } 复制代码
当我们查名字叫张三的学生参加的课程的时候,也能查到数学课。
GET /class_test/class_test/_search { "query": { "bool": { "must": [ { "match": { "student.name": "张三" } } ] } } }复制代码
{ "took" : 4, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 1, "max_score" : 0.5753642, "hits" : [ { "_index" : "class_test", "_type" : "class_test", "_id" : "ijfJ5GoBJeNZPNCWykLR", "_score" : 0.5753642, "_source" : { "id" : "1", "name" : "数学课", "student" : [ { "id" : "1", "name" : "张三" }, { "id" : "2", "name" : "李四" } ] } } ] } }复制代码
但是当我们查询id为1并且名字叫李四的学生参加的课程时
GET /class_test/class_test/_search { "query": { "bool": { "must": [ { "match": { "student.name": "李四" } }, { "match": { "student.id": "1" } } ] } } }复制代码
{ "took" : 6, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 1, "max_score" : 0.8630463, "hits" : [ { "_index" : "class_test", "_type" : "class_test", "_id" : "ijfJ5GoBJeNZPNCWykLR", "_score" : 0.8630463, "_source" : { "id" : "1", "name" : "数学课", "student" : [ { "id" : "1", "name" : "张三" }, { "id" : "2", "name" : "李四" } ] } } ] } } 复制代码
我们发现,出来的结果也是数学课,这就有点奇怪,因为并没有一个id为1并且名字是李四的学生,那就不应该有这么课。这是怎么回事?原来在es内部,object数组类型会被打平,简单来说我们输入的数组,实际存储的类型是:
"student.id":[1,2], "student.name":[张三,李四]复制代码
所以倒排索引的建立,也是按照这种打平的逻辑。这个时候我们可以借助Elasticsearch内的嵌套类型来解决问题。
3.Nested类型
和2中类似的,我们需要建一个测试索引,名字为class,不同的是student有了type字段,为 "type":"nested"。
PUT /class { "mappings":{ "class": { "properties": { "id": { "type": "keyword" }, "name": { "analyzer": "ik_max_word", "type": "text" }, "type":{ "type":"keyword" }, "student":{ "type":"nested", "properties": { "name":{ "analyzer": "ik_max_word", "type": "text" }, "id":{ "type":"keyword" } } } } } }, "settings":{ "index": { "refresh_interval": "1s", "number_of_shards": 5, "max_result_window": "10000000", "mapper": { "dynamic": "false" }, "number_of_replicas": 0 } } }复制代码
我们导入相同的数据,然后用搜索id为1并且名字为李四的学生的课程,这个时候我们看到搜索结果为空:
GET /class/class/_search { "query": { "bool": { "must": [ { "nested": { "path": "student", "query": { "bool": {"must": [ { "match": { "student.name": "李四" } }, { "match": { "student.id": "1" } } ]} } } } ] } } }复制代码
{ "took" : 3, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 0, "max_score" : null, "hits" : [ ] } } 复制代码
4.其他方式
其实解决这种跨domain的搜索还有一些其他方式,对于嵌套类型,其实是非常消耗Elasticsearch的性能的,我们可以选择将需要搜索字段的值打平存一个字段,或者对学生单独建立一个索引,然后去学生-班级映射关系表查询班级。这一块后面有机会再做介绍。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Go类型嵌套
- go语言嵌套类型的使用细节
- ElasticSearch-Nested嵌套类型解密
- Elasticsearch 7.x Nested 嵌套类型查询 | ES 干货
- Elasticsearch 7.x Nested 嵌套类型查询 | ES 干货
- Python 循环嵌套
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
An Introduction to Probability Theory and Its Applications
William Feller / Wiley / 1991-1-1 / USD 120.00
Major changes in this edition include the substitution of probabilistic arguments for combinatorial artifices, and the addition of new sections on branching processes, Markov chains, and the De Moivre......一起来看看 《An Introduction to Probability Theory and Its Applications》 这本书的介绍吧!