1.基于Term的查詢
Term是表達語義的最小單位,搜索和自然語言處理都用Term處理。
- Term級別的查詢:Term查詢、范圍查詢、存在性查詢、前綴查詢、通配符查詢。
- 在ES里面對于Term查詢,輸入不做分詞。將輸入當成一個整體,在倒排索引里面查找準確的詞。然后根據公式對文檔進行算分。
- 可以通過Constant Score,避免算分,并利用緩存提高性能。
案例
POST /products/_bulk
{"index":{"_id":1}}
{"product_id":"ABC-DEF","desc":"iPhone"}
{"index":{"_id":2}}
{"product_id":"ABC-bba","desc":"iPad"}
POST /products/_search
{
"query": {
"term": {
"desc": {
"value": "iPhone"http://查不到,"iphone"可以,
}
}
}
}
POST /products/_search
{
"query": {
"term": {
"product_id.keyword": {
"value": "ABC-bba"
}
}
}
}
忽略計算評分
{
"query": {
"constant_score": {
"filter": {
"term": {
"product_id.keyword": "ABC-bba"
}
}
}
}
}
2.基于全文的查詢
可以通過match、match phrase、query string這些類的查詢實現。
特點:
- 索引和搜索時都會進行分詞,查詢字符串先傳遞一個合適的分詞器,然后生成可供查詢的列表。
- 查詢,先對輸入分詞,對每個單詞逐個底層查詢,最終合并結果,并計算分數。
詳細內容見:http://www.lxweimin.com/p/8e70f80cca80
3.結構化搜索
3.1 結構化數據
- 布爾類型和數字類型是結構化的
- 文本也可以是結構化的
- 彩色筆可以有離散的顏色結合。
- 博客可能被標記了標簽。
- 電商網站上的商品的標識符,嚴格規定結構化的格式
3.2 ES的結構化搜索
- 布爾、時間、日期或者數字這類結構化數據:有精確的格式,可以進行邏輯操作。包括比較數字或者范圍比較,判斷兩個值大小。
- 結構化的文本可以做精確匹配或者部分匹配:Term查詢/Prefix前綴查詢。
- 結構化結果只有是或者否兩個值,可以根據場景需要決定是否打分。
范圍查詢案例:
POST products/_search
{
"query": {
"constant_score": {
"filter": {
"range": {
"price": {
"gte": 10,
"lte": 20
}
}
},
"boost": 1.2
}
}
}
4.相關性算分
搜索的相關性算法,描述了一個文檔和查詢語句的匹配程度,ES會對每個匹配的查詢條件做score,ES5以前用TF-IDF算法,現在用BM25/
一些基本概念:
詞頻(IF):檢索詞在一片文檔中出現的頻率。檢索詞出現的次數/文檔總字數。可以把各個詞頻(除去沒有用的詞)想加得到一個評分。
逆文檔頻率(IDF):log(全部文檔數/檢索詞出現過的文檔總數)
TF-IDF:本質就是將TF加權求和,TF(區塊鏈)IDF(區塊鏈)+TF(的)IDF(的)+TF(應用)*IDF(應用)
4.1通過Boosting控制相關度
- 當boost > 1時,打分的相關度相對性提升
- 當 0 < boost < 1,打分的權重相對性降低
- 當boost <0,貢獻負分
POST score_test/_search
{
"query": {
"boosting": {
"positive": {
"term": {
"content": "live"
}
},
"negative":{
"term":{
"content":"he"
}
},
"negative_boost":0.3
}
}
}
匹配帶live的,如果content字段里面包含了he,減分0.3
5. Query & Filter 多字段查詢
5.1 bool查詢
應用于多個字段,多個條件的符合查詢。
- 一個bool查詢是一個或者多個查詢的組合。
- 總共包括4中子句,其中兩種會影響算分,兩種不影響分數。
- 多個子句被合并為復合語句的時候,比如bool查詢,每個語句的評分都會合并到總評分。
- 同一個層級的條件具有相同的權重,可以調整嵌套結構控制算分
字段值 | 說明 |
---|---|
must | 必須匹配,貢獻算分 |
should | 選擇性匹配,貢獻算分 |
must_not | filter context查詢子句,必須不能匹配,不算評分 |
filter | filter context 必須匹配,但是不貢獻算分。 |
- 子查詢可以任意順序出現
- 可以嵌套多個查詢
- 如果沒有must條件,should必須至少滿足一條查詢
案例
GET movies/_search
{
"size": 20,
"query": {
"bool": {
"must": [
{"term": {
"title": {
"value": "bob"
}
}}
],
"filter": [
{
"range": {
"year": {
"gte": 1991,
"lte": 1994
}
}
}
],
"should": [
{"term": {
"id": {
"value": "3809"
}
}},
{"term": {
"id": {
"value": "1994"
}
}}
],
"minimum_should_match": 1
}
}
}
標題里面包含bob,發行時間在1991年到1994年,最好id是3809或者1994,should條件最少滿足一個。
嵌套案例,boost會增加。
GET movies/_search
{
"query": {
"bool": {
"should": [
{"bool": {
"must": [
{"term": {
"title": {
"value": "bob",
"boost": 1.1
}
}}
]
}}
]
}
}
}
5.2 單字符串多字段查詢
案例,查詢title或者year出現2012的電影,should換成must表示且。
GET movies/_search
{
"explain": true,
"query": {
"bool": {
"should": [
{"match": {"title": "2012" }},
{"match": {"year": "2012"}}
]
}
}
}
評分規則:
- 查詢should語句的兩個查詢
- 對兩個查詢的評分求和
- 乘以匹配語句的總數
- 除以所有的語句的總數
基于這個評分規則,可能評分可能不是自己想要的。可以使用Disjunction Max Query
,這樣就會選擇分數最佳的查詢的結果的值,返回,不再是相加。
5.3 Disjunction Max Query
GET search_test/_search
{
"query": {
"dis_max": {
"should": [
{"match": {"title": "php class" }},
{"match": {"body": "php class"}}
],
"tie_breaker": 0.7
}
}
}
找出最大值,然后把其他的評分乘以0.7,然后想加得到一個新的評分。
5.3 Mulit Match
5.3.1 最佳字段(best field)
當字段之間存在相互競爭,又相互關聯。類似title和body,評分來自最匹配的字段。
案例
POST movies/_search
{
"query": {
"multi_match": {
"type": "best_fields",
"query": "1993",
"fields": [
"title",
"id"
],
"minimum_should_match": 1
, "tie_breaker": 0.2
}
}
}
5.3.2 多字段(most field)
- 在主字段(english analyzer),抽取詞干,加入同義詞,以匹配更多的項。
- 相同的文本,加入子字段(standard analyzer),以提供更加精準的匹配。其他字段作為匹配文檔提高相關度的信號,匹配的字段越多越好。
案例
PUT /titles
{
"mappings": {
"properties": {
"title":{
"type": "text",
"analyzer": "english",
"fields": {
"std":{
"type":"text",
"analyzer":"standard"
}
}
}
}
}
}
std字段不會進行分詞,是對title的優化
查詢
GET /titles/_search
{
"query": {
"multi_match": {
"type": "most_fields",
"query": "1",
"fields": ["title^10","title.std"]
}
}
}
mostfield方式,title設置權重百分10。
5.3.3 混合字段(cross field)
對于某些實體,人名、地址。需要在多個字段中確定信息,單個字段只能作為整體的一部分。希望在列出的字段中盡可能找到多的詞。
案例
POST address/_search
{
"query": {
"multi_match": {
"query": "poland street w",
"fields": ["street","city","country","postcode"],
"type": "cross_fields",
"operator": "and"
}
}
}
相對于通過_copyto方式,減少了磁盤空間,同時可以在搜索的時候為單個字段提升權重
6 search template
將搜索定義成模板,定義和使用的案例如下
POST _scripts/tmdb
{
"script":{
"lang":"mustache",
"source":{
"_source":["title","overview"],
"size":20,
"query":{
"multi_match":{
"query":"{{q}}",
"field":["title","overview"]
}
}
}
}
}
POST tmdb/_search/template
{
"id":"tmdb",
"params": {
"q":"basketball with"
}
}
7 index alias
給索引創建一個別名,實現靈停機運維。通過別名,索引的改名和重建程序不用動。
POST _aliases
{
"actions": [
{
"add": {
"index": "movies",
"alias": "moveis-2019",
"filter": {
"range": {
"year": {
"gte": 2012
}
}
}
}
}
]
}