# term filter 搜索数据
要搜索数据,必须得先有数据,所以接下来会先把模拟数据创建出来
# 创建帖子数据
根据 用户ID、是否隐藏、帖子ID、发帖日期来搜索帖子
插入一些测试帖子数据
POST /forum/article/_bulk
{ "index": { "_id": 1 }}
{ "articleID" : "XHDK-A-1293-#fJ3", "userID" : 1, "hidden": false, "postDate": "2017-01-01" }
{ "index": { "_id": 2 }}
{ "articleID" : "KDKE-B-9947-#kL5", "userID" : 1, "hidden": false, "postDate": "2017-01-02" }
{ "index": { "_id": 3 }}
{ "articleID" : "JODL-X-1937-#pV7", "userID" : 2, "hidden": false, "postDate": "2017-01-01" }
{ "index": { "_id": 4 }}
{ "articleID" : "QQPX-R-3956-#aD8", "userID" : 2, "hidden": true, "postDate": "2017-01-02" }
2
3
4
5
6
7
8
9
初步来说,就先搞4个字段,因为整个 es 是支持 json document 格式的,所以说扩展性和灵活性非常之好。 如果后续随着业务需求的增加,要在 document 中增加更多的 field,那么我们可以很方便的随时添加field。
但是如果是在关系型数据库中,比如mysql,我们建立了一个表,现在要给表中新增一些 column,那就很坑爹了, 必须用复杂的修改表结构的语法去执行。而且可能对系统代码还有一定的影响。
查看 mappings
GET /forum/_mapping/article
2
响应
{
"forum": {
"mappings": {
"article": {
"properties": {
"articleID": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"hidden": {
"type": "boolean"
},
"postDate": {
"type": "date"
},
"userID": {
"type": "long"
}
}
}
}
}
}
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
articleID.keyword 解释
在 5.2 版本起,type = text,默认会设置两个 field:
原本的字段:articleID
不分词的字段:keyword
ignore_above:最多保留 256 个字符
可以通过
_analyze
来检测
GET /forum/_analyze
{
"field": "articleID.keyword",
"text": "XHDK-A-1293-#fJ3"
}
2
3
4
5
响应
{
"error": {
"root_cause": [
{
"type": "remote_transport_exception",
"reason": "[sEvAlYx][127.0.0.1:9300][indices:admin/analyze[s]]"
}
],
"type": "illegal_argument_exception",
"reason": "Can't process field [articleID.keyword], Analysis requests are only supported on tokenized fields"
},
"status": 400
}
2
3
4
5
6
7
8
9
10
11
12
13
# 使用 term 搜索
term:对搜索文本不分词,直接拿去倒排索引中匹配,你输入的是什么,就去匹配什么
这里就是把数据过滤出来,也不需要相关分数,可以使用 constant_score
根据用户ID搜索帖子
GET /forum/article/_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"userID": 1
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
搜索没有隐藏的帖子
GET /forum/article/_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"hidden": false
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
根据发帖日期搜索帖子
GET /forum/article/_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"postDate": "2017-01-01"
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
根据帖子ID搜索帖子
GET /forum/article/_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"articleID": "JODL-X-1937-#pV7"
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
会发现什么都搜不到
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 0,
"max_score": null,
"hits": []
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
这是因为,该字段是分词字段。查看分词
# 查看分词
GET /forum/_analyze
{
"field": "articleID",
"text": "XHDK-A-1293-#fJ3"
}
2
3
4
5
响应
{
"tokens": [
{
"token": "xhdk",
"start_offset": 0,
"end_offset": 4,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "a",
"start_offset": 5,
"end_offset": 6,
"type": "<ALPHANUM>",
"position": 1
},
{
"token": "1293",
"start_offset": 7,
"end_offset": 11,
"type": "<NUM>",
"position": 2
},
{
"token": "fj3",
"start_offset": 13,
"end_offset": 16,
"type": "<ALPHANUM>",
"position": 3
}
]
}
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
可以看到在 articleID 存储中,已经是分词的了。所以我们使用 term 不分词的肯定是匹配不上的。
前面说了 text 字段会自动 mapping 一个 keyword 字段
articleID.keyword,是 es 最新版本内置建立的 field,就是不分词的。
所以一个 articleID 过来的时候,会建立两次索引,一次是自己本身,是要分词的,分词后放入倒排索引; 另外一次是基于 articleID.keyword,不分词,保留 256个 字符最多,直接一个字符串放入倒排索引中。
对于 text 类型的字段就可以考虑使用 filed.keyword 字段来搜索
GET /forum/article/_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"articleID.keyword": "JODL-X-1937-#pV7"
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
结果是出来了,但是还有个问题,默认就保留 256个 字符。 所以尽可能还是自己去手动建立索引,指定 not_analyzed 吧。在最新版本的es中,不需要指定 not_analyzed 也可以,将 type=keyword 即可。
# 索引重建
DELETE /forum
PUT /forum
{
"mappings": {
"article":{
"properties": {
"articleID":{
"type": "string",
"index": "not_analyzed"
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
TIP
注意 type ,如果是 text,就算指定了 index=not_analyzed 也还是会分词的。
如上面这样指定之后,再次查看 mapping ,会发现被优化成了 keyword
GET /forum/_mapping
响应
{
"forum": {
"mappings": {
"article": {
"properties": {
"articleID": {
"type": "keyword"
},
"hidden": {
"type": "boolean"
},
"postDate": {
"type": "date"
},
"userID": {
"type": "long"
}
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
所以在创建索引的时候就可以直接使用 keyword 类型
PUT /forum
{
"mappings": {
"article":{
"properties": {
"articleID":{
"type": "keyword"
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
插入测试数据之后再次搜索就可以了
# 知识总结
term filter:根据 exact value 进行搜索,数字、boolean、date 天然支持
text 需要建索引时指定为 not_analyzed,才能用 term query
相当于 SQL 中的单个 where 条件
select * from forum.article where articleID='XHDK-A-1293-#fJ3'
1
2
3