0%

案例:一篇博客对应多个评论。

字段类型由object改为nested即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
PUT /my_index
{
"mappings": {
"blogpost": {
"properties": {
"comments": {
"type": "nested",
"properties": {
"name": { "type": "string" },
"comment": { "type": "string" },
"age": { "type": "short" },
"stars": { "type": "short" },
"date": { "type": "date" }
}
}
}
}
}
}

嵌套对象的查询

嵌套对象被索引在独立隐藏的文档中,所以必须使用nested查询去获取数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
GET /my_index/blogpost/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"title": "eggs"
}
},
{
"nested": {
"path": "comments",
"query": {
"bool": {
"must": [
{
"match": {
"comments.name": "john"
}
},
{
"match": {
"comments.age": 28
}
}
]
}
}
}
}
]
}
}
}

nested子句作用于嵌套字段comments。comments.name和comments.age子句操作在同一个嵌套文档中。

nested查询还可以多层嵌套。

默认情况下,根文档的分数是这些嵌套文档分数的平均值。可以通过设置 score_mode 参数来控制这个得分策略,相关策略有 avg (平均值), max (最大值), sum (加和) 和 none (直接返回 1.0 常数值分数)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
GET /my_index/blogpost/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"title": "eggs"
}
},
{
"nested": {
"path": "comments",
"score_mode": "max",
"query": {
"bool": {
"must": [
{
"match": {
"comments.name": "john"
}
},
{
"match": {
"comments.age": 28
}
}
]
}
}
}
}
]
}
}
}

如果nested查询放在filter子句中,则score_mode参数不再生效,因为filter不是打分查询。

使用嵌套字段排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
PUT /my_index/blogpost/2
{
"title": "Investment secrets",
"body": "What they don't tell you ...",
"tags": [ "shares", "equities" ],
"comments": [
{
"name": "Mary Brown",
"comment": "Lies, lies, lies",
"age": 42,
"stars": 1,
"date": "2014-10-18"
},
{
"name": "John Smith",
"comment": "You're making it up!",
"age": 28,
"stars": 2,
"date": "2014-10-16"
}
]
}

查询某个时间范围内,有评论的文章,并按stars升序排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
GET /_search
{
"query": {
"nested": {
"path": "comments",
"filter": {
"range": {
"comments.date": {
"gte": "2014-10-01",
"lt": "2014-11-01"
}
}
}
}
},
"sort": {
"comments.stars": {
"order": "asc",
"mode": "min",
"nested_path": "comments",
"nested_filter": {
"range": {
"comments.date": {
"gte": "2014-10-01",
"lt": "2014-11-01"
}
}
}
}
}
}

sort排序子句中的nested_path和nested_filter的查询条件和上面的path、filter重复。原因在于,排序发生在查询执行之后。我们是按某一时间范围
的stars数排序,而不是按所有时间的stars排序。比如blog1的在10月stars:1, blog2在10月stars:2,但blog1的所有stars:20,blog2的所有stars:10。
他们最后的结果是不一样的。

嵌套聚合

https://www.elastic.co/guide/cn/elasticsearch/guide/current/nested-aggregation.html

从关系型数据库迁移数据到Elasticsearch时,总要处理很多关联数据,如何进行数据建模,下面给出了四种方案可供大家参考。

其中最简单的一种就是数据冗余扁平化,这个不做过多讲解。

应用层联接有点类型关系型数据库的子查询。第一次查询的结果作为第二次查询的条件。

1
2
3
4
5
6
7
8
9
10
11
12
13
PUT /my_index/user/1 
{
"name": "John Smith",
"email": "john@smith.com",
"dob": "1970/10/24"
}

PUT /my_index/blogpost/2
{
"title": "Relationships",
"body": "It's complicated...",
"user": 1
}

blogpost 通过用户的 id 链接到用户。

通过用户的 ID 1 可以很容易的找到博客帖子。

1
2
3
4
5
6
7
8
9
10
GET /my_index/blogpost/_search
{
"query": {
"filtered": {
"filter": {
"term": { "user": 1 }
}
}
}
}

为了找到用户叫做 John 的博客帖子,我们需要运行两次查询。先查询名字包含 John 的所有用户的 id 集合,再像上面一样根据 id 查询 blogpost。

执行第一个查询得到的结果将填充到 terms 过滤器中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
GET /my_index/user/_search
{
"query": {
"match": {
"name": "John"
}
}
}

GET /my_index/blogpost/_search
{
"query": {
"filtered": {
"filter": {
"terms": { "user": [1, 3, 7] }
}
}
}
}

总结:应用层联接的主要优点是可以对数据进行标准化处理。缺点就是需要2次查询,有时间消耗。
如果说叫 John 的用户有很多,比如百万以上,那查询是非常没有效率的。
这种方法适合于 user 只有少量文档的情况,并且最好它们很少改变,这将允许应用程序对结果进行缓存,避免经常运行第一次查询。

eg. 搜索用户名称和博客标题,展示用户及其最相关的博客列表。

需要按用户名称进行分组,根据score进行排序选TOPN。

https://www.elastic.co/guide/cn/elasticsearch/guide/current/top-hits.html

eg. 文件目录的搜索,可以参考如下链接。

https://www.elastic.co/guide/cn/elasticsearch/guide/current/denormalization-concurrency.html

eg. 并发问题

https://www.elastic.co/guide/cn/elasticsearch/guide/current/concurrency-solutions.html

Windows10环境,某天突然就没法使用 git, svn了,IntelliJ IDEA下面的git, svn也没法正常使用。

使用git desktop时,提示cannot publish unborn HEAD

使用 cmd 时,也会提示信息 ANOMALY: use of REX.w is meaningless (default operand size is 64)

导致这个事情的原因是Win10的自动更新和某监控软件产生了冲突。

使用如下语句可以查看到这个软件的连接。

netstat -ano | findstr 8237

我们可以通过修改注册表的方式解决上述问题。

在运行中输入regedit打开注册表,然后打开到目录计算机\HKEY_LOCAL_MACHINE\SOFTWARE\TEC\Ocular.3\agent\config 下新建 字符串值
hookapi_filterproc_external,值为cmd.exe;powershell.exe;git.exe;idea64.exe

重启软件,一切恢复正常。