Elasticsearch 索引創建 / 數據查詢

  • es 6.0 開始不推薦一個index下多個type的模式,並且會在 7.0 中完全移除。在 6.0 的index下是無法創建多個type的,type帶來的字段類型衝突和檢索效率下降的問題,導致了type會被移除。(5.x到6.x)
  • _all字段也被捨棄了,使用 copy_to自定義聯合字段。(5.x到6.x)
  • type:text/keyword 來決定是否分詞,index: true/false決定是否索引(2.x到5.x)
  • analyzer來單獨設定分詞器(2.x到5.x)

創建索引

我們新建一個名news索引
設定默認分詞器爲ik分詞器用來處理中文
使用默認名 _doc 定義 type
關閉_source存儲(用來驗證 store 選項)
title 不存儲 author 不分詞 content 存儲

PUT /news
{
    "settings": {
        "number_of_shards": 5,
        "number_of_replicas": 1,
        "index": {
            "analysis.analyzer.default.type" : "ik_smart"
        }
    },
    "mappings": {
        "_doc": {
            "_source": {
                "enabled": false
            },
            "properties": {
                "news_id": {
                    "type": "integer",
                    "index": true
                },
                "title": {
                    "type": "text",
                    "store": false
                },
                "author": {
                    "type": "keyword"
                },
                "content": {
                    "type": "text",
                    "store": true
                },
                "created_at": {
                    "type": "date",
                    "format": "yyyy-MM-dd hh:mm:ss"
                }
            }
        }
    }
}
# 查看創建的結構
GET /news/_mapping

驗證分詞器是否生效

# 驗證分詞插件是否生效
GET /_analyze
{
    "analyzer": "ik_smart",
    "text": "我熱愛祖國"
}
GET /_analyze
{
    "analyzer": "ik_max_word",
    "text": "我熱愛祖國"
}
# 索引的默認分詞器
GET /news/_analyze
{
    "text": "我熱愛祖國!"
}
# 指定字段 分詞器將根據字段屬性做相應分詞處理
# author 爲 keyword 是不會做分詞處理
GET /news/_analyze
{
    "field": "author"
    "text": "我熱愛祖國!"
}
# title 的分詞結果
GET /news/_analyze
{
    "field": "title"
    "text": "我熱愛祖國!"
}

添加文檔

用於演示,後面的查詢會以這些文檔爲例。

POST /news/_doc
{
    "news_id": 1,
    "title": "我們一起學旺叫",
    "author": "才華橫溢王大貓",
    "content": "我們一起學旺叫,一起旺旺旺旺旺,在你面撒個嬌,哎呦旺旺旺旺旺,我的尾巴可勁兒搖",
    "created_at": "2019-03-26 11:55:20"
}
{
    "news_id": 2,
    "title": "我們一起學貓叫",
    "author": "王大貓不會被分詞",
    "content": "我們一起學貓叫,還是旺旺旺旺旺,在你面撒個嬌,哎呦旺旺旺旺旺,我的尾巴可勁兒搖",
    "created_at": "2019-03-26 11:55:20"
}
{
    "news_id": 3,
    "title": "實在編不出來了",
    "author": "王大貓",
    "content": "實在編不出來了,隨便寫點數據做測試吧,旺旺旺",
    "created_at": "2019-03-26 11:55:20"
}

檢索數據

match_all

即無檢索條件獲取全部數據

#無條件分頁檢索 以 news_id 排序
GET /news/_doc/_search
{
    "query": {
        "match_all": {}
    },
    "from": 0,
    "size": 2,
    "sort": {
        "news_id": "desc"
    }
}

因爲我們關掉了_source字段,即 ES 只會對數據建立倒排索引,不會存儲其原數據,所以結果裏沒有相關文檔原數據內容。關掉的原因主要是想演示highlight機制。

match

普通檢索,很多文章都說match查詢會對查詢內容進行分詞,其實並不完全正確,match查詢也要看檢索的字段type類型,如果字段類型本身就是不分詞的keyword(not_analyzed),那match就等同於term查詢了。

我們可以通過分詞器explain一下字段會被如何處理:

GET /news/_analyze
{
    "filed": "title",
    "text": "我會被如何處理呢?分詞?不分詞?"
}

查詢

GET /news/_doc/_search
{
    "query": {
        "match": {
            "title": "我們會被分詞"
        }
    },
    "highlight": {
        "fields": {
            "title": {}
        }
    }
}

通過highlight我們可以將檢索到的關鍵詞以高亮的方式返回上下文內容,如果關閉了_source就得開啓字段的store屬性存儲字段的原數據,這樣才能做高亮處理,不然沒有原內容了,也就沒辦法高亮關鍵詞了

multi_match

對多個字段進行檢索,比如我想查詢titlecontent中有我們關鍵詞的文檔,如下即可:

GET /news/_doc/_search
{
    "query": {
        "multi_match": {
            "query": "我們是好人",
            "fields": ["title", "content"]
        }
    },
    "highlight": {
        "fields": {
            "title": {},
            "content": {}
        }
    }
}

match_phrase

這個需要認證理解一下,match_phrase,短語查詢,何爲短語查詢呢?簡單來說即被查詢的文檔字段中要包含查詢內容被分詞解析後的所有關鍵詞,且關鍵詞在文檔中的分佈距離差offset要滿足slop設定的閾值。slop表徵可以將關鍵詞平移幾次來滿足在文檔中的分佈,如果slop足夠的大,那麼即便所有關鍵詞在文檔中分佈的很離散,也是可以通過平移滿足的。

content: i love china
match_phrase: i china
slop: 0//查不到 需要將 i china 的 china 關鍵詞 slop 1 後變爲 i - china 才能滿足
slop: 1//查得到

測試實例

# 先看下查詢會被如何解析分詞
GET /news/_analyze
{
    "field": "title",
    "text": "我們學"
}
# reponse
{
    "tokens": [
        {
            "token": "我們",
            "start_offset": 0,
            "end_offset": 2,
            "type": "CN_WORD",
            "position": 0
        },
        {
            "token": "學",
            "start_offset": 2,
            "end_offset": 3,
            "type": "CN_CHAR",
            "position": 1
        }
    ]
}
# 再看下某文檔的title是被怎樣建立倒排索引的
GET /news/_analyze
{
    "field": "title",
    "text": "我們一起學旺叫"
}
# reponse
{
    "tokens": [
        {
            "token": "我們",
            "start_offset": 0,
            "end_offset": 2,
            "type": "CN_WORD",
            "position": 0
        },
        {
            "token": "一起",
            "start_offset": 2,
            "end_offset": 4,
            "type": "CN_WORD",
            "position": 1
        },
        {
            "token": "學",
            "start_offset": 4,
            "end_offset": 5,
            "type": "CN_CHAR",
            "position": 2
        },
        ...
    ]
}

注意position字段,只有slop的閾值大於兩個不相鄰的關鍵詞的position差時,才能滿足平移關鍵詞查詢內容短語分佈的位置條件。

查詢內容被分詞爲:["我們", "學"],而文檔中["我們", "學"]兩個關鍵字的距離爲 1,所以,slop必須大於等於1,此文檔才能被查詢到。

使用查詢短語模式:

GET /news/_doc/_search
{
    "query": {
        "match_phrase": {
            "title": {
                "query": "我們學",
                "slop": 1
            }
        }
    },
    "highlight": {
        "fields": {
            "title": {}
        }
    }
}

查詢結果:

{
            ...
            {
                "_index": "news",
                "_type": "_doc",
                "_id": "if-CuGkBddO9SrfVBoil",
                "_score": 0.37229446,
                "highlight": {
                    "title": [
                        "<em>我們</em>一起<em>學</em>貓叫"
                    ]
                }
            },
            {
                "_index": "news",
                "_type": "_doc",
                "_id": "iP-AuGkBddO9SrfVOIg3",
                "_score": 0.37229446,
                "highlight": {
                    "title": [
                        "<em>我們</em>一起<em>學</em>旺叫"
                    ]
                }
            }
            ...
}

term

term要理解只是不對查詢條件分詞,作爲一個關鍵詞去檢索索引。但文檔存儲時字段是否被分詞建立索引由_mappings時設定了。可能有["我們", "一起"]兩個索引,但並沒有["我們一起"]這個索引,查詢不到。keyword類型的字段則存儲時不分詞,建立完整索引,查詢時也不會對查詢條件分詞,是強一致性的。

GET /news/_doc/_search
{
    "query": {
        "term": {
           "title": "我們一起" 
        }
    },
    "highlight": {
        "fields": {
            "title": {}
        }
    }
}

terms

terms則是給定多個關鍵詞,就好比人工分詞

{
    "query": {
        "terms": {
           "title": ["我們", "一起"]
        }
    },
    "highlight": {
        "fields": {
            "title": {}
        }
    }
}

滿足["我們", "一起"]任意關鍵字的文檔都能被檢索到。

wildcard

shell通配符查詢: ? 一個字符 * 多個字符,查詢倒排索引中符合pattern的關鍵詞。

查詢有兩個字符的關鍵詞的文檔

{
   "query": {
       "wildcard": {
               "title": "??"
       }
   },
   "highlight": {
        "fields": {
            "title": {},
            "content": {}
        }
    }
}

prefix

前綴查詢,查詢倒排索引中符合pattern的關鍵詞。

{
   "query": {
       "prefix": {
               "title": "我"
       }
   },
   "highlight": {
        "fields": {
            "title": {},
            "content": {}
        }
    }
}

regexp

正則表達式查詢,查詢倒排索引中符合pattern的關鍵詞。

查詢含有2 ~ 3 個字符的關鍵詞的文檔

{
   "query": {
       "regexp": {
               "title": ".{2,3}"
       }
   },
   "highlight": {
        "fields": {
            "title": {},
            "content": {}
        }
    }
}

bool

布爾查詢通過 bool鏈接多個查詢組合:
must:必須全滿足
must_not:必須全不滿足
should:滿足一個即可

{
   "query": {
        "bool": {
            "must": {
                "match": {
                    "title": "絕對要有我們"
                }
            },
            "must_not": {
                "term": {
                    "title": "絕對不能有我"
                }
            },
            "should": [
                {
                    "match": {
                        "content": "我們"
                    }
                },
                {
                    "multi_match": {
                        "query": "滿足",
                        "fields": ["title", "content"]
                    }
                },
                {
                    "match_phrase": {
                        "title": "一個即可"
                    }
                }
            ],
            "filter": {
                "range": {
                    "created_at": {
                        "lt": "2020-12-05 12:00:00",
                        "gt": "2019-01-05 12:00:00"
                    }
                }
            }
        }
   },
   "highlight": {
        "fields": {
            "title": {},
            "content": {}
        }
    }
}

filter

filter 通常情況下會配合match之類的使用,對符合查詢條件的數據進行過濾。

{
   "query": {
        "bool": {
            "must": {
                "match_all": {}
            },
            "filter": {
                "range": {
                    "created_at": {
                        "lt": "2020-12-05 12:00:00",
                        "gt": "2017-12-05 12:00:00"
                    }
                }
            }
        }
   }
}

或者單獨使用

{
   "query": {
       "constant_score" : {
            "filter": {
                "range": {
                    "created_at": {
                        "lt": "2020-12-05 12:00:00",
                        "gt": "2017-12-05 12:00:00"
                    }
                }
            }
       }
   }
}

多個過濾條件:2017-12-05 12:00:00 <= created_at < 2020-12-05 12:00:00 and news_id >= 2

{
   "query": {
       "constant_score" : {
            "filter": {
                "bool": {
                    "must": [
                        {
                            "range": {
                                "created_at": {
                                    "lt": "2020-12-05 12:00:00",
                                    "gt": "2017-12-05 12:00:00"
                                }
                            }
                        },
                        {
                            "range": {
                                "news_id": {
                                    "gte": 2
                                }
                            }
                        }
                    ]
                }
            }
       }
   }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章