es multi match_PHP 的ES搜索操作
生活随笔
收集整理的這篇文章主要介紹了
es multi match_PHP 的ES搜索操作
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
原文:https://blog.csdn.net/JineD/article/details/106650695
首先從ES的支持的字段說起,ES文檔中字段有多種類型 官方文檔。這幾個比較常用:text,keyword,integer,float,boolean,object,geo_point(地理坐標),geo_shape(描述地理區域),date.注:不要以為date只能表示 2015-01-01 這種類型,2015/01/01 12:10:30這種類型也一樣可以,不像MySQL里面時間還分很多種細分的類型,ES就一個date類型。注意:這里沒有列出array,在ES中,array不是一種單獨的類型,但是你可以往ES里面存數組,這個地方有點難以理解,舉個例子:文檔里面我要定義一個字段叫 friends ,用來存儲用戶的朋友列表,用 text 類型定義字段:'friends' => [ 'type' => 'text']看似這僅僅定義了一個text類型的字段,并不是我們想要的數組,重點解釋來了,雖然我們的friends是字符串類型,但是我們在存入數據的時候 往 friends里面存儲兩個或者三個字符串,他就變成數組了!其實這句話描述還是不準確,不是從字符串變成數組,而是多個字符串組成了一個數組!插入數據:$this->putDoc([ 'first_name' => $this->faker->name, 'last_name' => $this->faker->name, 'age' => $this->faker->numberBetween(20,80), 'height' => (float)($this->faker->numberBetween(160,200)/100), 'friends' => [ $this->faker->name(), $this->faker->name(), $this->faker->name(), $this->faker->name() ]]);這個putDoc來得有點突然是不是?因為這是延續上一篇文章的續集,請看上一篇文章 使用PHP操作ElasticSearch。注意:faker是用來隨機生成數據的,詳細信息參考谷歌。你看,friends明明是 text 類型,但是我在插入的時候插入了多條數據,他變成了一個字符串類型的集合,前面我說他是數組,這個地方我把他說成是集合,這回更準確了,因為數組在ES中查詢是不能保證順序的,所以集合更準確,官方文檔中也表示他更像集合。再說一下object,模板里面這樣定義:'info' => [ 'type' => 'object', 'properties' => [ 'country' => [ 'type' => 'text', 'analyzer' => 'ik_max_word' ], 'sex' => [ 'type' => 'keyword' ] ]]這里定義了一個對象文檔,指定了下面兩個屬性的基本信息,但是不代表這個對象就只能存儲兩個屬性,比如我還可以在添加文檔的時候往里面添加一個skin 膚色的字段,完全沒有問題,只不過這里定義的兩個字段我們設置了類型和具體的analyzer,沒有在這里定義,但是我們實際上添加了的字段比如skin,ES會自動設置正確的類型,以及默認的analyzer。存入數據:'info' => [ 'country' => ['中國','印度','法國','英國','瑞士','剛果共和國'][random_int(0,5)], 'sex' => ['男','女'][random_int(0,1)], 'skin' => ['白','黑','黃'][random_int(0,2)],]還有一個keyword,他和text都表示字符串,區別在于 keyword里面的值不會被分詞器分詞,text里面的值會被分詞器智能拆分,記住這一點,這一點非常重要,后面還會講到這個區別。在定義text字段的時候 analyzer和index你需要清楚的地方:'last_name' => [ 'type' => 'text', //'analyzer' => 'standard', // 這個地方不設置analyzer會默認standard //'index' => false]analyzer不設置analyzer會默認standard。對于老版本的 ES,這里的index允許設置為 analyzed/not_analyzed/no,大部分網絡上的文章都是這樣講的,但是,最新版本已經移除了這些選項,現在只能是 true或false,所以我建議當你有一點基礎后,通讀一下官方最新文檔,雖然是英文的。如果這里設置為false,這個字段不加入索引,不能在查詢條件中出現,默認為true等一下,這里突然發現有點不對勁,以前可以設置 分析/不分析/不索引,現在只能設置索引和不索引了,如果想實現索引且不分析,那keyword類型剛好符合,而text字段是為分析而生的。ES中的搜索分兩個概念,匹配和過濾匹配通常針對的是 text 類型的字段,而過濾針通常對的精確的類型,比如 integer,keyword,date等,之所以加了通常二字,說明他們之間沒有明確的規定,匹配可以去匹配data,integer等類型,過濾也可以去過濾text字段,通過匹配的方式去找精確類型通常不會出現什么問題,通過過濾去找text類型的數據通常會得到意外的結果。謹記:如果沒有特殊情況,匹配針對text類型,過濾針對其他類型,但是對于精確類型使用過濾的性能通常比匹配更高,所以能使用過濾的地方都過濾。注意:這里要區別一下MySQL中的過濾概念,MySQL中的過濾是對查找后的數據進行過濾,而在ES中,過濾和匹配都等同于MySQL中的查找,匹配適合查找模糊數據,過濾適合查找精確數據而已。為了簡化代碼,下面的搜索都基于一下這份代碼,更改的部分只是 $query:$params = [ 'index' => $this->index, 'type' => $this->type, 'body' => array_merge([ 'from' => $from, 'size' => $size ],$query)];常用的過濾:term(精確查找)查找倪玲為44的數據$query = [ 'query' => [ 'term' => [ 'age' => 44 ] ]];terms(精確查找多個字段)查找年齡為 44或55或66的數據$query = [ 'query' => [ 'terms' => [ 'age' => [44,55,66] ] ]];range(范圍查找)$query = [ 'query' => [ 'range' => [ 'age' => [ 'gt' => 43, 'lt' => 45 ] ] ]];exists(等同于MySQL中的 is not null),查找存在age屬性的文檔$query = [ 'query' => [ 'exists' => [ 'field' => 'age' ] ]];missing(等同于 MySQL中的 is null),注意:這個過濾方法在2.x版本就廢棄了,請使用 must_not 嵌套 exists 來實現bool(用來組合其他過濾條件,包含 must,must_not,should操作)$query = [ 'query' => [ 'bool' => [ 'should' => [ 'range' => [ 'height' => ['gt' => 1.8] ] ], 'must_not' => [ 'term' => [ 'info.sex' => '女' ] ], 'must' => [ [ 'term' => [ 'info.country' => '法國' ] ], [ 'term' => [ 'info.skin' => '白' ] ] ] ] ]];上面這個查詢的意思是,身高應該大于1.8,性別不能是女,國家是法國且膚色是黑色。這里country實際上是text類型,但是我任然通過過濾的方法找到了正確的值,但是這種方式是非常危險的,這里之所以找到了正確的值,是因為country類型很簡單,碰巧analyzer(這里用的ik,如果是standard就沒那么好運了)沒有對其進行拆分。常用的查詢:match(匹配一個字段)$query = [ 'query' => [ 'match' => [ 'height' => '1.8' ] ]];match_all(匹配所有文檔,相當于沒有條件)等于是 $query = []multi_match(匹配多個字段)匹配姓和名里面包含 'Riley Libby Preston' 的數據$query = [ 'query' => [ 'multi_match' => [ 'query' => 'Riley Libby Preston', 'fields' => ['first_name','last_name'] ] ]];bool(用來組合其他匹配條件,包含 must,must_not,should操作)$query = [ 'query' => [ 'bool' => [ 'should' => [ 'match' => [ 'height' => '1.8' ] ], 'must_not' => [ 'match' => [ 'info.sex' => '男' ] ] ] ]];在實際使用中,匹配和過濾都是混合搭配使用的,比如:$query = [ 'query' => [ 'bool' => [ 'should' => [ 'match' => [ 'height' => '1.8' ] ], 'must_not' => [ 'term' => [ 'info.sex' => '女' ] ], 'must' => [ [ 'match' => [ 'info.country' => '法國' ] ], [ 'match' => [ 'info.skin' => '白' ] ] ] ] ]];match時常會出現一些怪異的現象,如果你不清楚你用的analyzer,比如這個例子:$query = [ 'query' => [ 'bool' => [ 'must' => [ [ 'match' => [ 'last_name' => 'Hamill' ] ], [ 'match' => [ 'info.country' => '法國' ] ] ] ] ]];這個查詢的需求是選出last_name中匹配到Hamill并且國家匹配到法國的結果,但是查詢的結果是這樣的,last_name 的中包含 Hamill,在我們意料之中,但是 country出現了英國,法國等很多國家,這個太意外了,現在來改造一下這個 $query,很小的改造,只需要把法國改成法,再次查詢,這次的結果完美的實現了我們的需求。原因在于:文檔中的法國二字被analyzer拆分成 (法,國) 存儲在索引中,同理,英國被拆分為 (英,國),現在你搜索法國的時候,你的這個搜索詞默認會被拆分成 (法,國),然后拿著這兩個詞去分別查找,第一個法可以匹配所有法國,第二個國字可以匹配到英國,美國等所有包含國字的結果。現在你知道結果的形成原因了。這個很大程度上上取決于你使用的analyzer,不同的analyzer分詞的策略不一樣,所以你有必要先搞明白你用的分詞器。他的大概分詞策略,上面這個例子沒有指定analyzer,是ES默認的分詞器在起作用,當我指定analyzer為 ik_max_word后,情況發生了變化,這個時候法國被當成了一個整體,沒有被拆分。可以通過簡單的測試來看看具體分詞器的分詞方式:$params = [ 'body' => [ 'analyzer' => 'ik_max_word', //默認 standard 'text' => '我在廣場吃著炸雞' ]];return $this->EsClient->indices()->analyze($params);默認分詞器standard會把這句話簡單的拆分成單個字,而ik相對就更懂中文一點,拆分出來的詞更有語義化,大部分的analyzer對英文的分詞都基于空格拆分。想要獲取學習實戰、高并發、架構?、筆試面試資料請掃碼咨詢+薇薇微信總結
以上是生活随笔為你收集整理的es multi match_PHP 的ES搜索操作的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python 正则表达式 sub_pyt
- 下一篇: 操作多台_一支热电偶能否连接多台显示仪表