这个系列我们来跟着中华石杉老师来系统的学习下ES
课程地址: https://www.roncoo.com/view/55
需求背景: 一个普通的论坛,根据用户ID、是否隐藏、帖子ID、发帖日期来搜索帖子
我这里用的版本是ES6.4.1 , 只要是5.X以上的版本都使用。目前ES的版本已经到了7.0.
Kibana用的也是对应的kibana-6.4.1-windows-x86_64
Term Filter 不推荐使用了,推荐使用 Term Query
https://www.elastic.co/guide/en/elasticsearch/reference/6.4/query-dsl-term-filter.html#query-dsl-term-filter
6.4版本的 Term Query说明
https://www.elastic.co/guide/en/elasticsearch/reference/6.4/query-dsl-term-query.html
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" }
BULK API官网说明: https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
简单说下_bulk api , 批量执行,对执行的json串有严格的格式要求,不要格式化JSON串
直接在kibana的DevTool中执行上述JSON即可
返回结果
#! Deprecation: the default number of shards will change from [5] to [1] in 7.0.0; if you wish to continue using the default of [5] shards, you must manage this on the create index request or with an index template
{
"took": 1581,
"errors": false,
"items": [
{
"index": {
"_index": "forum",
"_type": "article",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1,
"status": 201
}
}
......篇幅原因,省略其他三个的显示
}
]
}
结果说明:
再看下_shard节点下的total和successful信息
通过head插件我们也可以窥之一二
POST /forum/article/_bulk
es会自动创建名为forum的index和名为article的 typeGET /forum/_mapping/article
执行:
GET /forum/_mapping/article
返回:
{
"forum": {
"mappings": {
"article": {
"properties": {
"articleID": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"hidden": {
"type": "boolean"
},
"postDate": {
"type": "date"
},
"userID": {
"type": "long"
}
}
}
}
}
}
我们重点来看下 articleID
"ignore_above": 256
)articleID.keyword,是es新版本内置建立的field,就是不分词的。所以一个articleID过来的时候,会建立两次索引,一次是自己本身,是要分词的,分词后放入倒排索引; 另外一次是基于articleID.keyword,不分词,保留256个字符最多,直接一个字符串放入倒排索引中。
所以term filter,对text过滤,可以考虑使用内置的field.keyword来进行匹配。但是有个问题,默认就保留256个字符。所以尽可能还是自己去手动建立索引,指定not_analyzed吧。在新版本的es中,不需要指定not_analyzed也可以,将type=keyword即可。
"articleID": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
查看下Dynamic mapping下,text类型的分词
GET /forum/_analyze
{
"field": "articleID",
"text": "XHDK-A-1293-#fJ3"
}
可以看到 articleID建立索引的时候,XHDK-A-1293-#fJ3被分词成了 xhdk,a,1293,fj3
默认是analyzed的text类型的field,建立倒排索引的时候,就会对所有的articleID分词,分词以后,原本的articleID就没有了,只有分词后的各个word存在于倒排索引中。所以根据XHDK-A-1293-#fJ3 去查询,肯定是在 xhdk,a,1293,fj3 中查找不到数据的。
GET /forum/_analyze
{
"field": "articleID.keyword",
"text": "XHDK-A-1293-#fJ3"
}
term,是不对搜索文本分词的,直接将输入的内容去倒排索引中匹配,XHDK-A-1293-#fJ3 --> XHDK-A-1293-#fJ3;但是articleID建立索引的时候,XHDK-A-1293-#fJ3 --> xhdk,a,1293,fj3 ,所以使用 articleID是查不到的, articleID.keyword 是可以查到的。 如下所示
term filter/query:对搜索文本不分词,直接拿去倒排索引中匹配,你输入的是什么,就去匹配什么。 比如说,如果对搜索文本进行分词的话,“helle world” --> “hello”和“world”,两个词分别去倒排索引中匹配 。 term,“hello world” --> “hello world”,直接去倒排索引中匹配“hello world”
这里我们不关心相关度即_score,仅仅是希望通过filter过滤出来数据,所以 使用了 constant_score , 设置相关度都是1.
先通过head插件看下数据
GET /forum/article/_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"userID": 1
}
}
}
}
}
Term Query的写法(推荐)
GET /forum/article/_search
{
"query": {
"term": {
"userID": "1"
}
}
}
GET /forum/article/_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"hidden": false
}
}
}
}
}
Term Query的写法(推荐)
{
"query": {
"term": {
"hidden": false
}
}
}
GET /forum/article/_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"postDate": "2017-01-02"
}
}
}
}
}
Term Query的写法(推荐)
GET /forum/article/_search
{
"query": {
"term": {
"postDate": "2017-01-02"
}
}
}
GET /forum/article/_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"articleID": "QQPX-R-3956-#aD8"
}
}
}
}
}
Term Query的写法(推荐)
GET /forum/article/_search
{
"query": {
"term": {
"articleID": "QQPX-R-3956-#aD8"
}
}
}
这种Dynamic mapping的情况,肯定是查找不到数据了,要么指定 articleID.keyword。 更推荐自己设置类型,设置成 not_analyzed,或者直接将articleID设置为keyword更加方便。
那我们按照自己设置字段类型keyword的方式来演示下吧
先删掉原来的forum索引
DELETE /forum
手动设置 articleID的类型为 keyword
PUT /forum
{
"mappings":{
"article":{
"properties":{
"articleID":{
"type":"keyword"
}
}
}
}
}
这样的话,就建好了一个 只有一个字段的type. 字段类型确定后无法修改,因为涉及到底层lucene的全文检索。 但是可以增加字段,通过如下的方式,_bulk写入数据的时候,新增几个字段,因为没有指定字段类型,所以是Dynamic Mapping的方式创建的
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" }
看下 field的类型
GET /forum/_mapping/article
再次查询下 ,指定articleID的类型为keyword,查询到了数据。
总结一下 term
(1)term filter:根据exact value进行搜索,数字、boolean、date天然支持 (2)text类型的字段需要建索引时指定为not_analyzed或者设置为keyword,才能用term query (3)term 相当于SQL中的单个where条件