1. 程式人生 > >elasticsearch多欄位搜尋

elasticsearch多欄位搜尋

多欄位搜尋

多字串查詢

  • boost 引數 “最佳” 值,較為簡單的方式就是不斷試錯,比較合理的區間處於 1 到 10 之間,當然也有可能是 15 。如果為 boost 指定比這更高的值,將不會對最終的評分結果產生更大影響,因為評分是被 歸一化的
GET /_search
{
  "query": {
    "bool": {
      "should": [
        { "match": {
            "title":  {
              "query": "War and Peace",
              "boost": 2
        }}},
        { "match"
: { "author": { "query": "Leo Tolstoy", "boost": 2 }}}, { "bool": { # 不寫在上面一層,是因為tarnslator理論是隻佔總評分的三分之一,在上面一層就是四分之一了 "should": [ { "match": { "translator": "Constance Garnett" }}, { "match"
: { "translator": "Louise Maude" }} ] }} ] } } }

最佳欄位

  • dis_max(Disjunction Max Query)查詢,意思是 或,指的是: 將任何與任一查詢匹配的文件作為結果返回,但只將最佳匹配的評分作為查詢的評分結果返回;為了理解這句話,做給小實驗
    1. 建立測試資料
DELETE my_index

PUT /my_index/my_type/1
{
    "title": "Quick brown fox rabbits",
    "body":  "Brown eats rabbits are commonly seen."
} PUT /my_index/my_type/2 { "title": "Keeping pets healthy", "body": "My quick brown fox eats rabbits on a regular basis." }
  1. 查詢比較
GET  /my_index/my_type/_search
{
    "query": {
        "bool": {
            "should": [
                { "match": { "title": "Brown fox eats" }},
                { "match": { "body":  "Brown fox eats" }}
            ]
        }
    }
}

結果:id為1的文件在前面
id1isfirst.

GET  /my_index/my_type/_search
{
    "query": {
        "dis_max": {            # dis_max查詢,文件查詢的某個match評分最高的作為結果返回
            "queries": [
                { "match": { "title": "Brown fox eats" }},
                { "match": { "body":  "Brown fox eats" }}
            ]
        }
    }
}

結果:
dis_max_sample

最佳欄位查詢調優

  • tie_breaker:一個簡單的 dis_max 查詢會採用單個最佳匹配欄位, 而忽略其他的匹配,指定 tie_breaker 這個引數可以將其他匹配語句的評分也考慮其中;比如:

    1. 簡單dis_max查詢
      {
          "query": {
              "dis_max": {
                  "queries": [
                      { "match": { "title": "Quick pets" }},
                      { "match": { "body":  "Quick pets" }}
                  ]
              }
          }
      }

    結果:
    sample_dismax

    1. tie_breaker
      GET /my_index/my_type/_search
      {
        "query": {
          "dis_max": {
            "queries": [
              {
                "match": {
                  "title": "Quick pets"
                }
              },
              {
                "match": {
                  "body": "Quick pets"
                }
              }
            ],
            "tie_breaker": 0.3
          }
        }
      }

    結果:
    tie_breaker

  • tie_breaker 引數提供了一種 dis_max 和 bool 之間的折中選擇,範圍[0,1]範圍建議0.1-0.4, 0 代表使用 dis_max 最佳匹配語句的普通邏輯, 1 表示所有匹配語句同等重要,步驟如下:

    1. 獲得最佳匹配語句的評分 _score
    2. 將其他匹配語句的評分結果與 tie_breaker 相乘
    3. 對以上評分求和並規範化

multi_match查詢

  • 為能在多個欄位上反覆執行相同查詢提供了一種便捷方式,multi_match 多匹配查詢的型別有多種,其中的三種恰巧與 瞭解我們的資料 中介紹的三個場景對應,即: best_fields 、 most_fields 和 cross_fields (最佳欄位、多數字段、跨欄位),預設情況下,查詢的型別是 best_fields , 這表示它會為每個欄位生成一個 match 查詢,然後將它們組合到 dis_max 查詢的內部
GET /my_index/my_type/_search
{
  "query": {
    "dis_max": {
      "queries": [
        {
          "match": {
            "title": {
              "query": "Quick brown fox",
              "minimum_should_match": "30%"
            }
          }
        },
        {
          "match": {
            "body": {
              "query": "Quick brown fox",
              "minimum_should_match": "30%"
            }
          }
        }
      ],
      "tie_breaker": 0.3
    }
  }
}

查詢等價於

GET /my_index/my_type/_search
{
  "query": {
    "multi_match": {
      "query": "Quick brown fox",
      "type": "best_fields",  # 預設為best_fields可以不指定
      "fields": [
        "title",
        "body"
      ],
      "tie_breaker": 0.3,
      "minimum_should_match": "30%"  # 這樣的引數會被傳遞到生成的 match 查詢中
    }
  }
}

結果:
multi_match

查詢欄位名稱的模糊匹配

  • 欄位名稱可以用模糊匹配的方式給出
{
    "multi_match": {
        "query":  "Quick brown fox",
        "fields": "*_title"
    }
}

提升單個欄位的權重

  • 可以使用 ^ 字元語法為單個欄位提升權重,在欄位名稱的末尾新增 ^boost
{
    "multi_match": {
        "query":  "Quick brown fox",
        "fields": [ "*_title", "chapter_title^2" ]
    }
}

多欄位對映

  • 是對我們的欄位索引兩次, 一次使用詞幹模式以及一次非詞幹模式
  • 新增多欄位對映
DELETE /my_index

PUT /my_index
{
    "settings": { "number_of_shards": 1 },
    "mappings": {
        "my_type": {
            "properties": {
                "title": {
                    "type":     "string",
                    "analyzer": "english",
                    "fields": {
                        "std":   {
                            "type":     "string",
                            "analyzer": "standard"
                        }
                    }
                }
            }
        }
    }
}
  • Put值
PUT /my_index/my_type/1
{ "title": "My rabbit jumps" }

PUT /my_index/my_type/2
{ "title": "Jumping jack rabbits" }
  • get title

GET /my_index/_search
{
   "query": {
        "match": {
            "title": "jumping rabbits"
        }
    }
}

# 結果命中2條
  • get title.std
GET /my_index/_search
{
   "query": {
        "match": {
            "title.std": "jumping rabbits"
        }
    }
}
# 結果命中1條
  • most_fields 合併兩次索引的評分,加權重
GET /my_index/_search
{
   "query": {
        "multi_match": {
            "query":  "jumping rabbits",
            "type":   "most_fields",
            "fields": [ "title^10", "title.std" ]
        }
    }
}

跨欄位實體搜尋

  • 當多個屬性結合起來決定一個事物的時候,可以使用multi_match查詢(依次查詢每個欄位並將每個欄位的匹配評分結果相加),比如
    以下欄位表示一個人資訊
{
    "street":   "5 Poland Street",
    "city":     "London",
    "country":  "United Kingdom",
    "postcode": "W1V 3DG"
}

可以如下查詢

{
  "query": {
    "bool": {
      "should": [
        { "match": { "street":    "Poland Street W1V" }},
        { "match": { "city":      "Poland Street W1V" }},
        { "match": { "country":   "Poland Street W1V" }},
        { "match": { "postcode":  "Poland Street W1V" }}
      ]
    }
  }
}

{
  "query": {
    "multi_match": {
      "query":       "Poland Street W1V",
      "type":        "most_fields",     # 合併所有匹配欄位的評分
      "fields":      [ "street", "city", "country", "postcode" ]
    }
  }
}
  • most_fields也存在些問題
    1. 是為多數字段匹配 任意 詞設計的,而不是在 所有欄位 中找到最匹配的
    2. 不能使用 operator 或 minimum_should_match 引數來降低次相關結果造成的長尾效應
    3. 詞頻對於每個欄位是不一樣的,而且它們之間的相互影響會導致不好的排序結果

自定義_all

  • copy_to 引數來實現給欄位新增自定義_all欄位
PUT /my_index
{
    "mappings": {
        "person": {
            "properties": {
                "first_name": {
                    "type":     "string",
                    "copy_to":  "full_name"
                },
                "last_name": {
                    "type":     "string",
                    "copy_to":  "full_name"
                },
                "full_name": {
                    "type":     "string"
                }
            }
        }
    }
}

可通過地址http://blog.csdn.net/jiao_fuyou/article/details/49800969來更深入學習_all

cross-fields跨欄位查詢

  • 自定義 _all 的方式是一個好的解決方案,只需在索引文件前為其設定好對映,然而還可以使用cross_fields 型別進行 multi_match 查詢

  • cross_fields 使用詞中心式(term-centric)的查詢方式,這與 best_fields 和 most_fields 使用欄位中心式(field-centric)的查詢方式非常不同

  • 欄位中心式
GET /_validate/query?explain
{
    "query": {
        "multi_match": {
            "query":       "peter smith",
            "type":        "most_fields",
            "operator":    "and",
            "fields":      [ "first_name", "last_name" ]
        }
    }
}

對於匹配的文件, peter 和 smith 都必須同時出現在相同欄位中,要麼是 first_name 欄位,要麼 last_name 欄位

(+first_name:peter +first_name:smith)
(+last_name:peter  +last_name:smith)
  • 詞中心式,詞 peter 和 smith 都必須出現,但是可以出現在任意欄位中,cross_fields 型別首先分析查詢字串並生成一個詞列表,然後它從所有欄位中依次搜尋每個詞
GET /_validate/query?explain
{
    "query": {
        "multi_match": {
            "query":       "peter smith",
            "type":        "cross_fields",
            "operator":    "and",
            "fields":      [ "first_name", "last_name" ]
        }
    }
}

為了讓 cross_fields 查詢以最優方式工作,所有的欄位都須使用相同的分析器

  • 採用 cross_fields 查詢與 自定義 _all 欄位 相比,其中一個優勢就是它可以在搜尋時為單個欄位提升權重
GET /books/_search
{
    "query": {
        "multi_match": {
            "query":       "peter smith",
            "type":        "cross_fields",
            "fields":      [ "title^2", "description" ]
        }
    }
}
  • 需要在 multi_match 查詢中避免使用 not_analyzed 欄位