天天看點

實時搜尋引擎Elasticsearch(3)——查詢API的使用

上一篇文章介紹了ES中的Rest API,本章将重點介紹ES中的查詢API的使用。由于筆者在實際項目僅僅将ES用作索引資料庫,并沒有深入研究過ES的搜尋功能。而且鑒于筆者的搜尋引擎知識有限,本文将僅僅介紹ES簡單(非全文)的查詢API。

筆者原本打算在本文中介紹聚合API的内容,但是寫着寫着發現文章有點過長,不便于閱讀,故将聚合API的内容移至下一篇部落格中。

引言

單單介紹理論和API是乏味和低效率的,本文将結合一個實際的例子來介紹這些API。下表是本文資料表的表結構,表名(type)為“student”。注意,studentNo是本表的id,也就是_id字段的值與studentNo的值保持一緻。

字段名 字段含義 類型 是否能被索引 備注
studentNo 學号 string id
name 姓名 string
sex 性别 string
age 年齡 integer
birthday 出生年月 date
address 家庭住址 string
classNo 班級 string
isLeader 是否為班幹部 boolean

上面的表結構所對應的mapping如下,将資料儲存在索引名為“student”的索引中。

{
  "student": {
    "properties": {
      "studentNo": {
        "type": "string",
        "index": "not_analyzed"
      },
      "name": {
        "type": "string",
        "index": "not_analyzed"
      },
      "male": {
        "type": "string",
        "index": "not_analyzed"
      },
      "age": {
        "type": "integer"
      },
      "birthday": {
        "type": "date",
        "format": "yyyy-MM-dd"
      },
      "address": {
        "type": "string",
        "index": "not_analyzed"
      },
      "classNo": {
        "type": "string",
        "index": "not_analyzed "
      },
      "isLeader": {
        "type": "boolean"
      }
    }
  }
}
           

索引中儲存的資料如下,下面介紹的所有API都将基于這個資料表。

studentNo name male age birthday classNo address isLeader
1 劉備 24 1985-02-03 1 湖南省長沙市 true
2 關羽 22 1987-08-23 2 四川省成都市 false
3 糜夫人 19 1990-06-12 1 上海市 false
4 張飛 20 1989-07-30 3 北京市 false
5 諸葛亮 18 1992-04-27 2 江蘇省南京市 true
6 孫尚香 16 1994-05-21 3 false
7 馬超 19 1991-10-20 1 黑龍江省哈爾濱市 false
8 趙雲 23 1986-10-26 2 浙江省杭州市 false

查詢API

ES中的查詢非常靈活,為使用者提供了非常友善而強大的API。個人覺得ES的調用接口設計得非常好,所有接口合理且風格一緻,值得好好研究!

Query和Filter

ES為使用者提供兩類查詢API,一類是在查詢階段就進行條件過濾的query查詢,另一類是在query查詢出來的資料基礎上再進行過濾的filter查詢。這兩類查詢的差別是:

  • query方法會計算查詢條件與待查詢資料之間的相關性,計算結果寫入一個score字段,類似于搜尋引擎。filter僅僅做字元串比對,不會計算相關性,類似于一般的資料查詢,是以filter得查詢速度比query快。
  • filter查詢出來的資料會自動被緩存,而query不能。

query和filter可以單獨使用,也可以互相嵌套使用,非常靈活。

Query查詢

下面的情況下适合使用query查詢:

  • 需要進行全文搜尋。
  • 查詢結果依賴于相關性,即需要計算查詢串和資料的相關性。

(1)Match All Query

查詢所有的資料,相當于不帶條件查詢。下面的代碼是一個典型的match_all查詢的調用方式。

curl -XPOST "192.168.1.101:9200/student/student/_search" -d 
'
{
  "query": {
    "match_all": {}
  }
}
'
           

查詢結果如下。其他所有的查詢都是傳回這種格式的資料。

{
  "took": ,                  // 查詢耗時(毫秒)
  "timed_out": false,           // 是否逾時
  "_shards": {
    "total": ,                 // 總共查詢的分片數
    "successful": ,            // 查詢成功的分片數
    "failed":                  // 查詢失敗的分片數
  },
  "hits": {
    "total": ,                 // 本次查詢的記錄數
    "max_score": ,             // 查詢所有資料中的最大score
    "hits": [                   // 資料清單
      {
        "_index": "student",    // 資料所屬的索引名
        "_type": "student",     // 資料所屬的type
        "_id": "4",             // 資料的id值
        "_score": ,            // 該記錄的score
        "_source": {            // ES将原始資料儲存到_source字段中
          "studentNo": "4",
          "name": "張飛",
          "male": "男",
          "age": "20",
          "birthday": "1989-07-30",
          "classNo": "3",
          "isLeader": "F"
        }
      },
      {
         ……                     // 其他的資料格式相同,就不列出來了
      }
    ]
  }
}
           

查詢時,你會發現無論資料量有多大,每次最多隻能查到10條資料。這是因為ES服務端預設對查詢結果做了分頁處理,每頁預設的大小為10。如果想自己指定查詢的資料,可使用from和size字段,并且按指定的字段排序。

curl -XPOST "192.168.1.101:9200/student/student/_search" -d 
'
{
  "query": {
    "match_all": {}
  },
  "from": ,        // 從2條記錄開始取
  "size": ,        // 取4條資料
  "sort": {
    "studentNo": {  // 按studentNo字段升序
      "order": "asc"// 降序為desc
    }
  } 
}
'
           
注意:不要把from設得過大(超過10000),否則會導緻ES服務端因頻繁GC而無法正常提供服務。其實實際項目中也沒有誰會翻那麼多頁,但是為了ES的可用性,務必要對分頁查詢的頁碼做一定的限制。

(2)term query

詞語查詢,如果是對未分詞的字段進行查詢,則表示精确查詢。查找名為“諸葛亮”的學生,查詢結果為學号為5的記錄。

curl -XPOST "192.168.1.101:9200/student/student/_search" -d 
'
{
  "query": {
    "term": {
      "name": "諸葛亮"
    }
  }
}
'
           

(3)Bool Query

Bool(布爾)查詢是一種複合型查詢,它可以結合多個其他的查詢條件。主要有3類邏輯查詢:

  • must:查詢結果必須符合該查詢條件(清單)。
  • should:類似于in的查詢條件。如果bool查詢中不包含must查詢,那麼should預設表示必須符合查詢清單中的一個或多個查詢條件。
  • must_not:查詢結果必須不符合查詢條件(清單)。

查找2班的班幹部,查詢結果為學号為5的記錄。

curl -XPOST "192.168.1.101:9200/student/student/_search" -d 
'
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "classNo": ""
          }
        },
        {
          "term": {
            "isLeader": "true"
          }
        }
      ]
    }
  }
}
'
           

(4)Ids Query

id字段查詢。查詢資料id值為1和2的同學,由于id的值與studentNo相同,故查詢結果為學号為1和2的學生。

curl -XPOST "192.168.1.101:9200/student/student/_search" -d 
'
{
  "query": {
    "ids": {
      "type": "student",
      "values": [
        "",
        ""
      ]
    }
  }
}
'
           

(5)Prefix Query

字首查詢。查找姓【趙】的同學,查詢結果是學号為8的趙雲。

curl -XPOST "192.168.1.101:9200/student/student/_search" -d 
'
{
  "query": {
    "prefix": {
      "name": "趙"
    }
  }
}
'
           

(6)Range Query

範圍查詢,針對date和number類型的資料。查找年齡到18~20歲的同學,查詢結果是學号為3、4、5、7的記錄。

curl -XPOST "192.168.1.101:9200/student/student/_search" -d 
'
{
  "query": {
    "range": {
      "age": {
        "gte": "18",     // 表示>=
        "lte": "20"      // 表示<=
      }
    }
  }
}
'
           
實際上,對于date類型的資料,ES中以其時間戳(長整形)的形式存放的。

(7)Terms Query

多詞語查詢,查找符合詞語清單的資料。如果要查詢的字段索引為not_analyzed類型,則terms查詢非常類似于關系型資料庫中的in查詢。下面查找學号為1,3的學生。

curl -XPOST "192.168.1.101:9200/student/student/_search" -d 
'
{
  "query": {
    "terms": {
      "studentNo": [
        "",
        ""
      ]
    }
  }
}
'
           

(8)Wildcard Query

通配符查詢,是簡化的正規表達式查詢,包括下面兩類通配符:

  • * 代表任意(包括0個)多個字元
  • ? 代表任意一個字元

查找名字的最後一個字是“亮”的同學,查詢結果是學号為5的諸葛亮。

curl -XPOST "192.168.1.101:9200/student/student/_search" -d 
'
{
  "query": {
    "wildcard": {
      "name": "*亮"
    }
  }
}
'
           

(9)Regexp Query同學

正規表達式查詢,這是最靈活的字元串類型字段查詢方式。查找家住長沙市的學生,查詢結果為學号為1的學生。

curl -XPOST "192.168.1.101:9200/student/student/_search" -d 
'
{
  "query": {
    "regexp": {
      "address": ".*長沙市.*"  // 這裡的.号表示任意一個字元
    }
  }
}
'
           

Filter查詢

下面的情況下适合使用filter查詢:

  • yes/no的二進制查詢
  • 針對精确值進行查詢

filter和query的查詢方式有不少是重疊的,是以本節僅僅介紹API的調用,一些通用的注意的事項就不再重複了。

(1)Term Filter

詞語查詢,如果是對未分詞的字段進行查詢,則表示精确查詢。查找名為“諸葛亮”的學生,查詢結果為學号為5的記錄。

curl -XPOST "192.168.1.101:9200/student/student/_search" -d 
'
{
  "filter": {               
    "term": {
      "name": "諸葛亮",
      "_cache" : true // 與query主要是這裡的差別,可以設定資料緩存
    }
  }
}
'
           

filter查詢方式都可以通過設定_cache為true來緩存資料。如果下一次恰好以相同的查詢條件進行查詢并且該緩存沒有過期,就可以直接從緩存中讀取資料,這樣就大大加快的查詢速度。

(2)Bool Filter

查找2班的班幹部,查詢結果為學号為5的記錄。

curl -XPOST "192.168.1.101:9200/student/student/_search" -d 
'
{
  "filter": {
    "bool": {
      "must": [
        {
          "term": {
            "classNo": ""
          }
        },
        {
          "term": {
            "isLeader": "true"
          }
        }
      ]
    }
  }
}
'
           

(3)And Filter

And邏輯連接配接查詢,連接配接1個或1個以上查詢條件。它與bool查詢中的must查詢非常相似。實際上,and查詢可以轉化為對應的bool查詢。查找2班的班幹部,查詢結果為學号為5的學生。

curl -XPOST "192.168.1.101:9200/student/student/_search" -d 
'
{
  "filter": {
      "and": [
        {
          "term": {
            "classNo": ""
          }
        },
        {
          "term": {
            "isLeader": "true"
          }
        }
      ]
  }
}
'
           

(4)Or Filter

Or連接配接查詢,表示邏輯或。。查找2班或者是班幹部的學生名單,查詢結果為學号為1、2、5、8的學生。

curl -XPOST "192.168.1.101:9200/student/student/_search" -d 
'
{
  "filter": {
      "or": [
        {
          "term": {
            "classNo": ""
          }
        },
        {
          "term": {
            "isLeader": "true"
          }
        }
      ]
  }
}
'
           

(5)Exists Filter

存在查詢,查詢指定字段至少包含一個非null值的資料。如果字段索引為not_analyzed類型,則查詢sql中的is not null查詢方式。查詢位址存在學生,查詢結果為除了6之外的所有學生。

curl -XPOST "192.168.1.101:9200/student/student/_search" -d 
'
{
  "filter": {
    "exists": {
      "field": "address"
    }
  }
}
'
           

(6)Missing Filter

缺失值查詢,與Exists查詢正好相反。查詢位址不存在的學生,查詢結果為學号為6的學生。

curl -XPOST "192.168.1.101:9200/student/student/_search" -d 
'
{
  "filter": {
    "missing": {
      "field": "address"
    }
  }
}
'
           

(7)Prefix Filter

字首查詢。查找姓【趙】的同學,查詢結果是學号為8的趙雲。

curl -XPOST "192.168.1.101:9200/student/student/_search" -d 
'
{
  "filter": {
    "prefix": {
      "name": "趙"
    }
  }
}
'
           

(8)Range Filter

範圍查詢,針對date和number類型的資料。查找年齡到18~20歲的同學,查詢結果是學号為3、4、5、7的記錄。

curl -XPOST "192.168.1.101:9200/student/student/_search" -d 
'
{
  "filter": {
    "range": {
      "age": {
        "gte": "",
        "lte": ""
      }
    }
  }
}
'
           

(9)Terms Filter

多詞語查詢,查找符合詞語清單的資料。如果要查詢的字段索引為not_analyzed類型,則terms查詢非常類似于關系型資料庫中的in查詢。下面查找學号為1,3的學生。

curl -XPOST "192.168.1.101:9200/student/student/_search" -d 
'
{
  "filter": {
    "terms": {
      "studentNo": [
        "",
        ""
      ]
    }
  }
}
'
           

(10)Regexp Filter

正規表達式查詢,是最靈活的字元串類型字段查詢方式。查找家住長沙市的學生,查詢結果為學号為1的學生。

curl -XPOST "192.168.1.101:9200/student/student/_search" -d 
'
{
  "filter": {
    "regexp": {
      "address": ".*長沙市.*"
    }
  }
}
'
           

總結

本文介紹了ES中的部分查詢API,這些API是一些常用的簡單API,如果需要使用更加複雜一點的API,請查閱官網文檔。下一篇文章準備介紹ES中的聚合API的使用。

繼續閱讀