《ElasticSearch6.x實戰教程》之簡單搜索、Java客戶端(上)

来源:https://www.cnblogs.com/yulinfeng/archive/2019/07/20/11219786.html
-Advertisement-
Play Games

第五章 簡單搜索 眾里尋他千百度 搜索是ES的核心,本節講解一些基本的簡單的搜索。 掌握ES搜索查詢的RESTful的API猶如掌握關係型資料庫的SQL語句,儘管Java客戶端API為我們不需要我們去實際編寫RESTful的API,但在生產環境中,免不了線上上執行查詢語句做數據統計供產品經理等使用。 ...


第五章-簡單搜索

眾里尋他千百度

搜索是ES的核心,本節講解一些基本的簡單的搜索。

掌握ES搜索查詢的RESTful的API猶如掌握關係型資料庫的SQL語句,儘管Java客戶端API為我們不需要我們去實際編寫RESTful的API,但在生產環境中,免不了線上上執行查詢語句做數據統計供產品經理等使用。

數據準備

首先創建一個名為user的Index,並創建一個student的Type,Mapping映射一共有如下幾個欄位:

  1. 創建名為user的Index PUT http://localhost:9200/user

  2. 創建名為student的Type,且指定欄位name和address的分詞器為ik_smart

    POST http://localhost:9200/user/student/_mapping
    {
     "properties":{
         "name":{
             "type":"text",
             "analyzer":"ik_smart"
         },
         "age":{
             "type":"short"
         }
     }
    }

經過上一章分詞的學習我們把text類型都指定為ik_smart分詞器。

插入以下數據。

POST localhost:9200/user/student
{
    "name":"kevin",
    "age":25
}
POST localhost:9200/user/student
{
    "name":"kangkang",
    "age":26
}
POST localhost:9200/user/student
{
    "name":"mike",
    "age":22
}
POST localhost:9200/user/student
{
    "name":"kevin2",
    "age":25
}
POST localhost:9200/user/student
{
    "name":"kevin yu",
    "age":21
}

按查詢條件數量維度

無條件搜索

GET http://localhost:9200/user/student/_search?pretty

查看索引user的student類型數據,得到剛剛插入的數據返回:

單條件搜索

ES查詢主要分為term精確搜索、match模糊搜索。

term精確搜索

我們用term搜索name為“kevin”的數據。

POST http://localhost:9200/user/student/_search?pretty
{
    "query":{
        "term":{
            "name":"kevin"
        }
    }
}

既然term是精確搜索,按照非關係型資料庫的理解來講就等同於=,那麼搜索結果也應該只包含1條數據。然而出乎意料的是,搜索結果出現了兩條數據:name="kevin"和name="keivin yu",這看起來似乎是進行的模糊搜索,但又沒有搜索出name="kevin2"的數據。我們先繼續觀察match的搜索結果。

match模糊搜索

同樣,搜索name為“kevin”的數據。

POST http://localhost:9200/user/student/_search?pretty
{
    "query":{
        "match":{
            "name":"kevin"
        }
    }
}

match的搜索結果竟然仍然是兩條數據:name="kevin"和name="keivin yu"。同樣,name="kevin2"也沒有出現在搜索結果中。

原因在於termmatch的精確和模糊針對的是搜索詞而言,term搜索不會將搜索詞進行分詞後再搜索,而match則會將搜索詞進行分詞後再搜索。例如,我們對name="kevin yu"進行搜索,由於term搜索不會對搜索詞進行搜索,所以它進行檢索的是"kevin yu"這個整體,而match搜索則會對搜索詞進行分詞搜索,所以它進行檢索的是包含"kevin"和"yu"的數據。而name欄位是text類型,且它是按照ik_smart進行分詞,就算是"kevin yu"這條數據由於被分詞後變成了"kevin"和"yu",所以term搜索不到任何結果。

如果一定要用term搜索name="kevin yu",結果出現"kevin yu",辦法就是在定義映射Mapping時就為該欄位設置一個keyword類型。

為了下文的順利進行,刪除DELETE http:localhost:9200/user/student重新按照開頭創建索引以及插入數據吧。唯一需要修改的是在定義映射Mapping時,name欄位修改為如下所示:

{
    "properties":{
          "name":{
              "type":"text",
              "analyzer":"ik_smart",
              "fields":{
                  "keyword":{
                      "type":"keyword",
            "ignore_abore":256
                  }
              }
          },
    "age":{
        "type":integer
    }
    }
}

待我們重新創建好索引並插入數據後,此時再按照term搜索name="kevin yu"。

POST http://localhost:9200/user/student/_search
{
    "query":{
        "term":{
            "name.keyword":"kevin yu"
        }
    }
}

返回一條name="kevin yu"的數據。按照match搜索同樣出現name="kevin yu",因為name.keyword無論如何都不會再分詞。

在已經建立索引且定義好映射Mapping的情況下,如果直接修改name欄位,此時能修改成功,但是卻無法進行查詢,這與ES底層實現有關,如果一定要修改要麼是新增欄位,要麼是重建索引。

所以,與其說match是模糊搜索,倒不如說它是分詞搜索,因為它會將搜索關鍵字分詞;與其將term稱之為模糊搜索,倒不如稱之為不分詞搜索,因為它不會將搜索關鍵字分詞。

match查詢還有很多更為高級的查詢方式:match_phrase短語查詢,match_phrase_prefix短語匹配查詢,multi_match多欄位查詢等。將在複雜搜索一章中詳細介紹。

類似like的模糊搜索

wildcard通配符查詢。

POST http://localhost:9200/user/student/_search?pretty
{
  "query": {
    "wildcard": {
      "name": "*kevin*"
    }
  }
}

ES返回結果包括name="kevin",name="kevin2",name="kevin yu"。

fuzzy更智能的模糊搜索

fuzzy也是一個模糊查詢,它看起來更加”智能“。它類似於搜狗輸入法中允許語法錯誤,但仍能搜出你想要的結果。例如,我們查詢name等於”kevin“的文檔時,不小心輸成了”kevon“,它仍然能查詢出結構。

POST http://localhost:9200/user/student/_search?pretty
{
  "query": {
    "fuzzy": {
      "name": "kevin"
    }
  }
}

ES返回結果包括name="kevin",name="kevin yu"。

多條件搜索

上文介紹了單個條件下的簡單搜索,並且介紹了相關的精確和模糊搜索(分詞與不分詞)。這部分將介紹多個條件下的簡單搜索。

當搜索需要多個條件時,條件與條件之間的關係有”與“,”或“,“非”,正如非關係型資料庫中的”and“,”or“,“not”。

在ES中表示”與“關係的是關鍵字must,表示”或“關係的是關鍵字should,還有表示表示”非“的關鍵字must_not

mustshouldmust_not在ES中稱為bool查詢。當有多個查詢條件進行組合查詢時,此時需要上述關鍵字配合上文提到的termmatch等。

  1. 精確查詢(term,搜索關鍵字不分詞)name="kevin"age="25"的學生。
POST http://localhost:9200/user/student/_search?pretty
{
    "query":{
        "bool":{
            "must":[{
                "term":{
                    "name.keyword":"kevin"
                }
            },{
                "term":{
                    "age":25
                }
            }]
        }
    }
}

返回name="kevin"且age="25"的數據。

  1. 精確查詢(term,搜索關鍵字不分詞)name="kevin"age="21"的學生。
POST http://localhost:9200/user/student/_search?pretty
{
    "query":{
        "bool":{
            "should":[{
                "term":{
                    "name.keyword":"kevin"
                }
            },{
                "term":{
                    "age":21
                }
            }]
        }
    }
}

返回name="kevin",age=25和name="kevin yu",age=21的數據

  1. 精確查詢(term,搜索關鍵字不分詞)name!="kevin"age="25"的學生。
POST http://localhost:9200/user/student/_search?pretty
{
    "query":{
        "bool":{
            "must":[{
                "term":{
                    "age":25
                }
            }],
            "must_not":[{
                "term":{
                    "name.keyword":"kevin"
                }
            }]
        }
    }
}

返回name="kevin2"的數據。

如果查詢條件中同時包含mustshouldmust_not,那麼它們三者是"且"的關係

多條件查詢中查詢邏輯(mustshouldmust_not)與查詢精度(termmatch)配合能組合成非常豐富的查詢條件。

按等值、範圍查詢維度

上文中講到了精確查詢、模糊查詢,已經"且","或","非"的查詢。基本上都是在做等值查詢,實際查詢中還包括,範圍(大於小於)查詢(range)、存在查詢(exists)、~不存在查詢(missing

範圍查詢

範圍查詢關鍵字range,它包括大於gt、大於等於gte、小於lt、小於等於lte

  1. 查詢age>25的學生。
POST http://localhost:9200/user/student/_search?pretty
{
    "query":{
        "range":{
            "age":{
                "gt":25
            }
        }
    }
}

返回name="kangkang"的數據。

  1. 查詢age >= 21且age < 26的學生。
POST http://localhost:9200/user/search/_search?pretty
{
    "query":{
        "range":{
            "age":{
                "gte":21,
                "lt":25
            }
        }
    }
}

查詢age >= 21 且 age < 26且name="kevin"的學生

POST http://localhost:9200/user/search/_search?pretty
{
    "query":{
        "bool":{
            "must":[{
                "term":{
                    "name":"kevin"
                }
            },{
                "range":{
                    "age":{
                        "gte":21,
                        "lt":25
                    }
                }
            }]
        }
    }
}

存在查詢

存在查詢意為查詢是否存在某個欄位。

查詢存在name欄位的數據。

POST http://localhost:9200/user/student/_search?pretty
{
    "query":{
        "exists":{
            "field":"name"
        }   
    }
}

不存在查詢

不存在查詢顧名思義查詢不存在某個欄位的數據。在以前ES有missing表示查詢不存在的欄位,後來的版本中由於must notexists可以組合成missing,故去掉了missing

查詢不存在name欄位的數據。

POST http://localhost:9200/user/student/_search?pretty
{
    "query":{
        "bool":{
            "must_not":{
                "exists":{
                    "field":"name"
                }
            }
        }   
    }
}

分頁搜索

談到ES的分頁永遠都繞不開深分頁的問題。但在本章中暫時避開這個問題,只說明在ES中如何進行分頁查詢。

ES分頁查詢包含fromsize關鍵字,from表示起始值,size表示一次查詢的數量。

  1. 查詢數據的總數
POST http://localhost:9200/user/student/_search?pretty

返迴文檔總數。

  1. 分頁(一頁包含1條數據)模糊查詢(match,搜索關鍵字不分詞)name="kevin"
POST http://localhost:9200/user/student/_search?pretty
{
    "query":{
        "match":{
            "name":"kevin"
        }
    },
    "from":0,
    "size":1
}

結合文檔總數即可返回簡單的分頁查詢。

分頁查詢中往往我們也需要對數據進行排序返回,MySQL中使用order by關鍵字,ES中使用sort關鍵字指定排序欄位以及降序升序。

  1. 分頁(一頁包含1條數據)查詢age >= 21且age <=26的學生,按年齡降序排列。
POST http://localhost:9200/user/student/_search?pretty
{
    "query":{
        "range":{
            "age":{
                "gte":21,
                "lte":26
            }
        }
    },
    "from":0,
    "size":1,
    "sort":{
        "age":{
            "order":"desc"
        }
    }
}

ES預設升序排列,如果不指定排序欄位的排序),則sort欄位可直接寫為"sort":"age"

第六章-Java客戶端(上)

ES提供了多種方式使用Java客戶端:

  • TransportClient,通過Socket方式連接ES集群,傳輸會對Java進行序列化
  • RestClient,通過HTTP方式請求ES集群

目前常用的是TransportClient方式連接ES服務。但ES官方表示,在未來TransportClient會被永久移除,只保留RestClient方式。

同樣,Spring Boot官方也提供了操作ES的方式Spring Data ElasticSearch。本章節將首先介紹基於Spring Boot所構建的工程通過Spring Data ElasticSearch操作ES,再介紹同樣是基於Spring Boot所構建的工程,但使用ES提供的TransportClient操作ES。

Spring Data ElasticSearch

本節完整代碼(配合源碼使用更香):https://github.com/yu-linfeng/elasticsearch6.x_tutorial/tree/master/code/spring-data-elasticsearch

使用Spring Data ElasticSearch後,你會發現一切變得如此簡單。就連連接ES服務的類都不需要寫,只需要配置一條ES服務在哪兒的信息就能開箱即用

作為簡單的API和簡單搜索兩章節的啟下部分,本節示例仍然是基於上一章節的示例

通過IDEA創建Spring Boot工程,並且在創建過程中選擇Spring Data ElasticSearch,主要步驟如下圖所示:

第一步,創建工程,選擇Spring Initializr

第二步,選擇SpringBoot的依賴NoSQL -> Spring Data ElasticSearch

idea-springboot-es

創建好Spring Data ElasticSearch的Spring Boot工程後,按照ES慣例是定義Index以及Type和Mapping。在Spring Data ElasticSearch中定義Index、Type以及Mapping非常簡單。ES文檔數據實質上對應的是一個數據結構,也就是在Spring Data ElasticSearch要我們把ES中的文檔數據模型與Java對象映射關聯。

定義StudentPO對象,對象中定義Index以及Type,Mapping映射我們引入外部json文件(json格式的Mapping就是在簡單搜索一章中定義的Mapping數據)。

package com.coderbuff.es.easy.domain;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.Mapping;

import java.io.Serializable;

/**
 * ES mapping映射對應的PO
 * Created by OKevin on 2019-06-26 22:52
 */
@Getter
@Setter
@ToString
@Document(indexName = "user", type = "student")
@Mapping(mappingPath = "student_mapping.json")
public class StudentPO implements Serializable {

    private String id;

    /**
     * 姓名
     */
    private String name;

    /**
     * 年齡
     */
    private Integer age;
}

Spring Data ElasticSearch為我們屏蔽了操作ES太多的細節,以至於真的就是開箱即用,它操作ES主要是通過ElasticsearchRepository介面,我們在定義自己具體業務時,只需要繼承它,擴展自己的方法。

package com.coderbuff.es.easy.dao;

import com.coderbuff.es.easy.domain.StudentPO;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;

/**
 * Created by OKevin on 2019-06-26 23:45
 */
@Repository
public interface StudentRepository extends ElasticsearchRepository<StudentPO, String> {
}

ElasticsearchTemplate可以說是Spring Data ElasticSearch最為重要的一個類,它對ES的Java API進行了封裝,創建索引等都離不開它。在Spring中要使用它,必然是要先註入,也就是實例化一個bean。而Spring Data ElasticSearch早為我們做好了一切,只需要在application.properties中定義spring.data.elasticsearch.cluster-nodes=127.0.0.1:9300,就可大功告成(網上有人的教程還在使用applicationContext.xml定義一個bean,事實證明,受到了Spring多年的“毒害”,Spring Boot遠比我們想象的智能)。

單元測試創建Index、Type以及定義Mapping。

package com.coderbuff.es;

import com.coderbuff.es.easy.domain.StudentPO;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringDataElasticsearchApplicationTests {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    /**
     * 測試創建Index,type和Mapping定義
     */
    @Test
    public void createIndex() {
        elasticsearchTemplate.createIndex(StudentPO.class);
        elasticsearchTemplate.putMapping(StudentPO.class);
    }
}

使用GET http://localhost:9200/user請求命令,可看到通過Spring Data ElasticSearch創建的索引。

索引創建完成後,接下來就是定義操作student文檔數據的介面。在StudentService介面的實現中,通過組合StudentRepository類對ES進行操作。StudentRepository類繼承了ElasticsearchRepository介面,這個介面的實現已經為我們提供了基本的數據操作,保存、修改、刪除只是一句代碼的事。就算查詢、分頁也為我們提供好了builder類。"最難"的實際上不是實現這些方法,而是如何構造查詢參數SearchQuery。創建SearchQuery實例,有兩種方式:

  1. 構建NativeSearchQueryBuilder類,通過鏈式調用構造查詢參數。
  2. 構建NativeSearchQuery類,通過構造方法傳入查詢參數。

這裡以"不分頁range範圍和term查詢age>=21且age<26且name=kevin"為例。

SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.boolQuery()
                        .must(QueryBuilders.rangeQuery("age").gte(21).lt(26))
                        .must(QueryBuilders.termQuery("name", "kevin"))).build();

搜索條件的構造一定要對ES的查詢結構有比較清晰的認識,如果是在瞭解了簡單的API簡單搜索兩章的前提下,學習如何構造多加練習一定能掌握。這裡就不一一驗證前面章節的示例,一定要配合代碼使用練習(https://github.com/yu-linfeng/elasticsearch6.x_tutorial/tree/master/code/spring-data-elasticsearch)

TransportClient

ES的Java API非常廣泛,一種操作可能會有好幾種寫法。Spring Data ElasticSearch實際上是對ES Java API的再次封裝,從使用上將更加簡單。

本節請直接對照代碼學習使用,如果要講解ES的Java API那將是一個十分龐大的工作,https://github.com/yu-linfeng/elasticsearch6.x_tutorial/tree/master/code/transportclient-elasticsearch

關註公眾號:CoderBuff,回覆“es”獲取《ElasticSearch6.x實戰教程》完整版PDF。

這是一個能給程式員加buff的公眾號 (CoderBuff)
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 舉個慄子 問題描述 股民炒股票 簡單實現 股票1 其他股票 測試 測試結果 外觀模式 定義 為了子系統中的一組介面提供一個一致的界面,此模式定義了一個高層的介面,這個介面使得這個子系統更加容易使用。 UML圖 代碼實現 基金類(Facade) 測試 測試結果同上,此處省略。 總結 首先,在設計初期階 ...
  • Spring Cloud Alibaba | Sentinel: 服務限流高級篇 Springboot: 2.1.6.RELEASE SpringCloud: Greenwich.SR1 如無特殊說明,本系列文章全採用以上版本 [TOC] 上一篇 "《Spring Cloud Alibaba | S ...
  • 黑馬程式員49期java全套視頻 黑馬程式員49期java全套視頻 下載地址http://www.pythonheidong.com/blog/article/2061/ ...
  • 下載地址 下載地址 ...
  • # list 列表 # 中括弧括起來,逗號分隔每個元素, # 列表中可以是數字字元串、列表等都可以放進去 list1 = [123, "book", "手動", ["data", 123, "文件"], 232, "tool", 'age', True] # list提供的方法 # 1 索引取值 p... ...
  • 題目鏈接:https://www.luogu.org/problemnew/show/P1330 思路:參考過大佬的思路,第一次用染色思想寫題。提取題目的關鍵: (1)一條邊相連的點只至少有一個被占領。 (2)相鄰兩個點不能都被占領。 (1) + (2) ——> (3)相鄰兩個點有且只有一個點要被占 ...
  • 1、settings.INSTALLED_APPS下添加:django.contrib.staticfiles 2、settings.py下添加:STATIC_URL = '/static/' 3、 (1)在APP下新建文件夾static,然後在這個static文件夾下創建一個當前APP的名字的文件... ...
  •   Java虛擬機採用可達性分析演算法來判斷對象是否可以回收。可達性分析演算法通過一系列的GC Roots對象作為起始點,向下搜索走過的路徑稱引用鏈,當一個對象到GC Roots沒有任何的引用鏈時,證明對象是不可用的。 Java中,可作為GC Roots的對象: 虛擬機棧中引用的對象 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...