久久精品精选,精品九九视频,www久久只有这里有精品,亚洲熟女乱色综合一区
    分享

    ElasticSearch的學習筆記并整合SpringBoot做測試

     印度阿三17 2021-03-01

    ElasticSearch的學習

    簡介

    ElasticSearch是一個分布式的開源搜索和分析引擎,MySQL專攻于數據的持久化存儲與管理(即CRUD),在真正要處理海量數據的檢索與分析時,ElasticSearch是更勝一籌的,可以秒級地從海量數據中檢索出需要需要的數據,而MySQL如果單表達到百萬以上的數據再進行檢索是非常慢的。

    ElasticSearch功能有很多,包括各種檢索功能(應用程序搜索、網站搜索、企業搜索)、對檢索來的數據做處理分析(特別是日志處理和分析)、應用指標的監控、數據的分析和可視化等。

    ElasticSearchm是目前全文搜索引擎的首選,可以快速地存儲、搜索和分析海量數據。數據默認放在內存中

    其底層是用以前Apache的開源庫Lucene,對Lucene做了再一次的簡化封裝,直接提供REST API的操作接口,比如直接給ElasticSearch發請求就可以使用其復雜的檢索功能。

    官方文檔

    一、基本概念

    1、Index(索引)

    動詞,相當于MySQL中的insert,在MySQL中插入一條數據 = 在ElasticSearch中索引一條數據;

    名詞,相當于MySQL中的Database,MySQL中的庫 = ElasticSearch的索引

    2、Type(類型)【根據當前ES版本最新文檔,“Before 7.0.0, the mapping definition included a type name. Elasticsearch 7.0.0 and later no longer accept a default mapping. See Removal of mapping types.”,類型已被移除。具體原因及解決見 Mapping 知識塊】

    在Index(索引)中,可以定義一個或多個類型;

    類似于MySQL中的Table;每一種類型的數據放在一起

    3、Document

    保存在某個索引(Index)下,某種類型(Type)的一個數據(Document),文檔是JSON格式的,Document就像是MySQL中的某個Table里面的內容(一條條的記錄)

    4、ElasticSearch概念 — 倒排索引機制

    分詞:將整句分拆為單詞;

    將拆分出來的單詞和該單詞出現的記錄存放在ElasticSearch額外維護的倒排索引表中

    檢索:拆分檢索的數據為單詞,在倒排索引表中查詢這些單詞分別在哪些記錄中

    相關性得分,將相關性得分高的記錄數據查出來

    二、docker安裝ElasticSearch

    修改 Linux 網絡設置
    [root@localhost ~]# cd /etc/sysconfig/network-scripts/
    [root@localhost network-scripts]# ls
    ifcfg-eth0  ifdown-bnep  ifdown-isdn    ifdown-sit       ifup          ifup-ippp  ifup-plusb   ifup-sit       ifup-wireless
    ifcfg-eth1  ifdown-eth   ifdown-post    ifdown-Team      ifup-aliases  ifup-ipv6  ifup-post    ifup-Team      init.ipv6-global
    ifcfg-lo    ifdown-ippp  ifdown-ppp     ifdown-TeamPort  ifup-bnep     ifup-isdn  ifup-ppp     ifup-TeamPort  network-functions
    ifdown      ifdown-ipv6  ifdown-routes  ifdown-tunnel    ifup-eth      ifup-plip  ifup-routes  ifup-tunnel    network-functions-ipv6
    [root@localhost network-scripts]# ip addr
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        inet 127.0.0.1/8 scope host lo
           valid_lft forever preferred_lft forever
        inet6 ::1/128 scope host 
           valid_lft forever preferred_lft forever
    2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
        link/ether 52:54:00:4d:77:d3 brd ff:ff:ff:ff:ff:ff
        inet 10.0.2.15/24 brd 10.0.2.255 scope global noprefixroute dynamic eth0
           valid_lft 83062sec preferred_lft 83062sec
        inet6 fe80::5054:ff:fe4d:77d3/64 scope link 
           valid_lft forever preferred_lft forever
    3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
        link/ether 08:00:27:87:53:b1 brd ff:ff:ff:ff:ff:ff
        inet 192.168.56.10/24 brd 192.168.56.255 scope global noprefixroute eth1
           valid_lft forever preferred_lft forever
        inet6 fe80::a00:27ff:fe87:53b1/64 scope link 
           valid_lft forever preferred_lft forever
    4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
        link/ether 02:42:da:49:0e:5c brd ff:ff:ff:ff:ff:ff
        inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
           valid_lft forever preferred_lft forever
        inet6 fe80::42:daff:fe49:e5c/64 scope link 
           valid_lft forever preferred_lft forever
    6: veth9f2577f@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
        link/ether 4a:e1:fa:70:da:a3 brd ff:ff:ff:ff:ff:ff link-netnsid 1
        inet6 fe80::48e1:faff:fe70:daa3/64 scope link 
           valid_lft forever preferred_lft forever
    8: veth938fc84@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
        link/ether 2a:e1:8c:3b:bc:66 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet6 fe80::28e1:8cff:fe3b:bc66/64 scope link 
           valid_lft forever preferred_lft forever
    12: vethb2c64c0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
        link/ether 0e:fa:e2:77:1a:62 brd ff:ff:ff:ff:ff:ff link-netnsid 3
        inet6 fe80::cfa:e2ff:fe77:1a62/64 scope link 
           valid_lft forever preferred_lft forever
    18: veth9f373db@if17: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
        link/ether 1e:42:ad:3e:88:f2 brd ff:ff:ff:ff:ff:ff link-netnsid 2
        inet6 fe80::1c42:adff:fe3e:88f2/64 scope link 
           valid_lft forever preferred_lft forever
    [root@localhost network-scripts]# vi ifcfg-eth1
    
    #VAGRANT-BEGIN
    # The contents below are automatically generated by Vagrant. Do not modify.
    NM_CONTROLLED=yes
    BOOTPROTO=none
    ONBOOT=yes
    IPADDR=192.168.56.10
    NETMASK=255.255.255.0
    GATEWAY=192.168.56.1# 設置網關
    DNS1=114.114.114.114# 公共DNS,用于解析域名
    DNS2=8.8.8.8
    DEVICE=eth1
    PEERDNS=no
    #VAGRANT-END
    
    [root@localhost network-scripts]# service network restart
    
    修改 Linux 的 yum 源
    1. 備份原 yum 源
    2. 使用新 yum 源
    3. 生成緩存
    [root@localhost network-scripts]# mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
    [root@localhost network-scripts]# curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.163.com/.help/CentOS7-Base-163.repo
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100  1572  100  1572    0     0   3849      0 --:--:-- --:--:-- --:--:--  3852
    [root@localhost network-scripts]# yum makecache
    Loaded plugins: fastestmirror
    Determining fastest mirrors
    base | 3.6 kB  00:00:00     
    docker-ce-stable | 3.5 kB  00:00:00     
    extras | 2.9 kB  00:00:00     
    updates | 2.9 kB  00:00:00     
    (1/11): base/7/x86_64/other_db | 2.6 MB  00:00:01     
    (2/11): base/7/x86_64/filelists_db | 7.2 MB  00:00:01     
    (3/11): docker-ce-stable/7/x86_64/filelists_db |  24 kB  00:00:05     
    (4/11): extras/7/x86_64/filelists_db | 226 kB  00:00:00     
    (5/11): extras/7/x86_64/other_db | 134 kB  00:00:00     
    (6/11): extras/7/x86_64/primary_db | 225 kB  00:00:00     
    (7/11): updates/7/x86_64/primary_db | 5.6 MB  00:00:00     
    (8/11): updates/7/x86_64/other_db | 454 kB  00:00:00     
    (9/11): updates/7/x86_64/filelists_db | 3.4 MB  00:00:00     
    (10/11): docker-ce-stable/7/x86_64/other_db | 117 kB  00:00:01     
    (11/11): docker-ce-stable/7/x86_64/primary_db |  56 kB  00:00:09     
    Metadata Cache Created
    

    1、下載鏡像文件

    docker pull elasticsearch:7.10.1#存儲和檢索數據,相當于MySQL服務
    docker pull kibana:7.10.1#可視化檢索數據,相當于SQLyog
    

    兩個鏡像版本需統一

    2、創建實例

    1)、Elasticsearch
    mkdir -p /mydata/elasticsearch/config  
    #將在docker容器中的ElasticSearch所有的配置文件信息都掛載在外面虛擬機中的/mydata/elasticsearch/config文件夾下,通過修改虛擬機/mydata/elasticsearch/config中配置文件的配置信息,就能修改docker容器中ElasticSearch的配置
    
    mkdir -p /mydata/elasticsearch/data
    #同樣將ElasticSearch中的一些數據文件掛載在外面虛擬機中的/mydata/elasticsearch/data文件夾下。
    
    echo "http.host: 0.0.0.0" >> /mydata/elasticsearch/config/elasticsearch.yml        
    #將http.host: 0.0.0.0寫入elasticsearch.yml配置文件中,以便ElasticSearch可以讓遠程的任何機器進行訪問
    
    #如果在之后一部步啟動elasticsearch容器報錯,并無法通過瀏覽器訪問elasticsearch的9200端口訪問到信息,可以查看日志排查,如是文件權限問題,進行以下修改。也可以事先進行文件權限修改
    docker logs elasticsearch#查看elasticsearch啟動的日志
    ll /mydata/elasticsearch/#查看/mydata/elasticsearch/目錄下的文件的權限,包括config、data、plugins
    #發現三個文件都為drwxr-xr-x權限,文件所有人(這里是root用戶)可讀可寫可執行rwx,文件所有組和其他人只有可讀和可執行的權限r-x。
    #解讀drwxr-xr-x:
    #第1位 d代表文件類型,-:普通文件,d:目錄文件,l:鏈接文件,b:設備文件,c:字符設備文件,p:管道文件
    #第2-4位rwx代表文件所有者(屬主)有可讀可寫可執行的權限
    #第5-7位r-x代表文件所有組(屬組,與屬主同一組的用戶)有可讀可執行的權限
    #第8-10位r-x代表其他人有可讀可執行的權限
    #r:可讀,數字表示為4;w:可寫,數字表示為2;x:可執行,數字表示為1。
    chmod -R 777 /mydata/elasticsearch/   #chmod是修改權限的命令;-R是可選項,表示遞歸;777表示將任何用戶任何組的權限改為可讀可寫可執行,對應了三個角色;改的是/mydata/elasticsearch/目錄下的所有文件
    #-R是命令可選項,參考如下說明:
    #-c : 若該文件權限確實已經更改,才顯示其更改動作
    #-f : 若該文件權限無法被更改也不要顯示錯誤訊息
    #-v : 顯示權限變更的詳細資料
    #-R : 對目前目錄下的所有文件與子目錄進行相同的權限變更(即以遞回的方式逐個變更)
    #--help : 顯示輔助說明
    #--version : 顯示版本
    
    docker run --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" -v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /mydata/elasticsearch/data:/usr/share/elasticsearch/data -v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins -d elasticsearch:7.10.1
    #--name elasticsearch表示為ElasticSearch鏡像起個名字為elasticsearch;
    #-p 9200:9200 -p 9300:9300暴露了兩個端口,一個為9200,一個為9300。9200是后來由REST API向ElasticSearch的9200端口發送http請求,9300是ElasticSearch在分布式集群狀態下節點之間的通信端口
    #-e "discovery.type=single-node"ElasticSearch以單節點模式運行
    #-e ES_JAVA_OPTS="-Xms64m -Xmx512m"很重要!如果不指定該條,ElasticSearch一啟動會將內存全部占用,會導致整個虛擬機卡死,因此在此指定Xms64m初始內存為64兆,最大占用內存為512兆(測試期間夠用,但真正服務上線后,公司的檢索服務器內存一般都是32G左右,因此可以給ElasticSearch多分配)
    #-v /mydata/elasticsearch/config/elasticsearch.yml:/user/share/elasticsearch/config/elasticsearch.yml -v是進行掛載,相當于將容器中ElasticSearch中的所有配置,跟外部虛擬機創建的配置文件進行一一關聯,以后修改外部的就相當于修改容器內的。包括掛載data數據目錄、plugins插件目錄
    #-d elasticsearch:7.10.1最后-d用elasticsearch:7.10.1鏡像啟動ElasticSearch
    
    2)、Kibana
    docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.56.10:9200 -p 5601:5601 -d kibana:7.10.1
    #-e修改參數ELASTICSEARCH_HOSTS,修改ES主機地址修改為自己虛擬機的地址
    #-p映射到端口5601,通過訪問5601端口訪問到kibana的可視化界面
    #然后從可視化界面,kibana把請求發送給ES的http://192.168.56.10:9200
    

    三、初步檢索

    *:http://192.168.56.10:9200

    1、_cat

    GET */cat/nodes# 查看所有節點
    
    GET */_cat/health# 查看ES健康狀況
    
    GET */_cat/master# 查看主節點
    
    GET */_cat/indices# 查看所有索引show databases;
    

    2、索引一個文檔(保存記錄)

    保存一個數據,保存在哪個索引的哪個記錄下,指定用哪個唯一標識

    PUT customer/external/1;在customer索引下的external類型下保存1號數據為:

    PUT */customer/external/1# postman發送請求:
    
    {"name":"Cyril_P"} # 并帶上數據:
    

    PUT請求和POST請求都可以保存數據,但是PUT請求必須帶上id,POST請求可以不帶id。

    如果POST請求不指定id,會自動生成id;如果指定id,并且該id之前沒數據就會新增,繼續指定該id,就會修改這個數據,并新增版本號

    PUT可以新增可以修改,但PUT必須指定id;由于PUT需要指定id,我們一般都用來做修改操作,PUT不指定id會報錯

    3、查詢文檔

    GET */customer/external/1
    
    {// 帶下劃線'_'表示元數據
        "_index": "customer",// 在哪個索引
        "_type": "external",// 在哪個類型
        "_id": "1",// 記錄id
        "_version": 1,// 版本號
        "_seq_no": 0,// 并發控制字段,每次更新就會 1,用來做樂觀鎖
        "_primary_term": 1,// 同上,主分片重新分配,如重啟,就會變化,用來做樂觀鎖
        "found": true,// 為true,代表找到數據
        "_source": {// 查詢到的真正內容
            "name": "Cyril_P"
        }
    }
    

    樂觀鎖處理多個修改請求,更新文檔uri需攜帶 ?if_seq_no=0&if_primary_trem=1

    4、更新文檔

    POST */customer/external/1/_update
    
    {"doc": {"name": "PrPrPr"}}
    
    會對比原來數據,與原來一樣就什么都不做,version、seq_no都不變;

    POST */customer/external/1/
    
    {"doc": {"name": "PrPrPr"}}
    
    直接更新數據,version和seq_no會改變;

    PUT */customer/external/1/
    
    {"doc": {"name": "PrPrPr"}}
    
    直接更新數據,version和seq_no會改變。
    更新同時增加屬性,以上三個都可以:

    {“doc”: {“name”: “PrPrPr”,“age”:21}}

    5、刪除文檔&索引

    DELETE */customer/external/1/
    
    DELETE */customer
    

    6、bulk批量API 【在這之后的請求體無法在postman中測試,均移步至Kibana上測試】

    POST /customer/external/_bulk
    
    {"index":{"_id":"1"}}   # index表示插入動作
    {"name":"Cyril_P"}
    {"index":{"_id":"2"}}
    {"name":"PrPrPrPr"}
    

    語法格式:

    {action:{metadata}}

    {requestbody}

    {action:{metadata}}

    {requestbody}

    復雜實例:(metadata前帶有"_",此處markdown沒有顯示,index、type和id前都有)

    POST /_bulk
    
    {"delete":{"_index":"website","_type":"blog","_id":"123"}}# delete表示刪除動作
    {"create":{"_index":"website","_type":"blog","_id":"123"}}# create表示創建動作
    {"title":"My First Blog POST"}# 真正的內容
    {"index":{"_index":"website","_type":"blog"}}# index表示插入動作
    {"title":"My Second Blog POST"}# 真正的內容
    {"update":{"_index":"website","_type":"blog","_id":"123","retry_on_conflict":3}}# update表示更新動作
    {"doc":{"title":"My Updated Blog POST"}}# 真正的內容
    

    四、進階檢索

    1、SearchAPI

    ES支持兩種基本方式檢索:

    一個是通過使用 REST request URI 發送搜索參數(uri 檢索參數);

    另一個是通過使用 REST request body 來發送它們(uri 請求體)。

    1)、檢索信息
    • 一切檢索從 _search 開始
    GET /bank/_search# 檢索bank下所有信息,包括type和docs
    
    GET /bank/_search?q=*&sort=account_number:asc# 請求參數方式檢索
    

    響應結果解釋:

    took —— ElasticSearch執行搜索的時間(毫秒)

    time_out —— 表示搜索是否超時

    _shards —— 表示多少個分片被搜索了,以及統計了成功/失敗的搜索分片

    hits —— 搜索結果

    hits.total —— 搜索結果

    hits.hits —— 實際的搜索結果數組(默認為前10的文檔)

    sort —— 結果的排序key(鍵)(沒有則按score排序)

    score 和 max_score —— 相關性得分和最高得分(全文檢索用)

    • uri 請求體進行檢索
    GET/bank/_search
    {
      "query": {
        "match_all": {}
      },
      "sort": [
        {
          "account_number": "asc"
        }
      ]
    }
    

    HTTP 客戶端工具(postman),GET 請求不能攜帶請求體,我們變為 POST 也是一樣的,我們 POST 一個 JSON 格式的查詢請求體到_search API。

    需要了解,一旦搜索的結果被返回,ElasticSearch 就完成了這次請求,并且不會維護任何服務端的資源或者結果的 cursor(游標)。

    2、Query DSL

    1)、基本語法格式

    ElasticSearch 提供了一個可以執行查詢的 JSON 格式的 DSL(domain-specific language 領域特定語言),這個被稱為 Query DSL。

    • Query DSL 的典型結構如下:
    {
    QUERY_NAME:{
    ARGUMENT:VALUE,
    ARGUMENT:VALUE,...
    }
    }
    
    • 如果是針對某個字段,那么結構如下:
    {
    QUERY_NAME:{
    FILED_NAME:{
    ARGUMENT:VALUE,
    ARGUMENT:VALUE,...
    }
    }
    }
    

    案例:

    GET /bank/_search
    {
      "query": {
        "match_all": {}
      },
      "sort": [
        {
          "balance": {
            "order": "desc"
          }
        }
      ],
      "from": 0,
      "size": 5
    }
    
    • query 定義如何查詢;
    • match_all 查詢類型【代表查詢所有的所有】,ES中可以在query中組合非常多的查詢類型完成復雜查詢;
    • 除了query參數之外,我們也可以傳遞其他的參數以改變查詢結果。如sort、size等;
    • from size 限定數,完成分頁功能;
    • sort 排序,多字段排序,會在前序字段相等時后續字段內部排序,否則以前序字段為準。
    2)、返回部分字段

    案例:

    GET /bank/_search
    {
      "query": {
        "match_all": {}
      },
      "sort": [
        {
          "balance": {
            "order": "desc"
          }
        }
      ],
      "from": 0,
      "size": 5,
      "_source": ["account_number","balance"]
    }
    
    • 真正內容"_source"只查詢"account_number"、"balance"兩個字段
    3)、match【匹配查詢】
    • 基本類型(非字符串),精準匹配
    GET /bank/_search
    {
      "query": {
        "match": {
          "account_number": "20"
        }
      }
    }
    

    match返回 account_number = 20 的文檔。

    • 字符串,全文檢索(如是單詞便進行全文檢索;如多個單詞的字符串,會先進行分詞,并進行全文檢索;都會根據相關性得分排序)
    GET /bank/_search
    {
      "query": {
        "match": {
          "address": "mill lane"
        }
      }
    }
    

    會對檢索條件"mill lane"進行分詞匹配,最終查詢出 address 中包含 "mill "或者 "lane "或者 “mill lane” 的所有文檔,并給出相關性得分,全文檢索按照相關性得分進行排序。

    4)、match_phrase【短語匹配】

    將需要匹配的值當成一個整體單詞(不分詞)進行檢索。

    GET /bank/_search
    {
      "query": {
        "match_phrase": {
          "address": "mill lane"
        }
      }
    }
    

    查出 address 中包含 “mill lane” 的所有文檔,并給出相關性得分,全文檢索按照相關性得分進行排序。

    5)、multi_match【多字段匹配】
    GET /bank/_search
    {
      "query": {
        "multi_match": {
          "query": "mill movico",
          "fields": ["address","city"]
        }
      }
    }
    

    會對 “mill movico” 進行分詞,查出 address 或者 city 包含 "mill "或者 "movico "或者 “mill movico” 的所有文檔。

    6)、bool【復合查詢】

    bool 用來做復合查詢:

    復合語句可以合并任何其他查詢語句,包括復合語句,意味著 復合語句之間可以互相嵌套,表達非常復雜的邏輯。

    must、must_not、should:
    • must:必須達到 must 列舉的所有條件

    • should:應該達到 should 列舉的所有條件,如果達到會增加相關文檔的評分(相關性得分),并不會改變查詢的結果。如果 query 中只有 should 且只有一種匹配規則,那么 should 的條件就會被作為默認匹配條件而去改變查詢結果

    • must_not:必須不是指定的情況

    GET /bank/_search
    {
      "query": {
        "bool": {
          "must": [
            {"match": {
              "gender": "M"
            }},
            {"match": {
              "address": "mill"
            }}
          ],
          "must_not": [
            {"match": {
              "age": "18"
            }}
          ],
          "should": [
            {"match": {
              "lastname": "Hines"
            }}
          ]
        }
      }
    }
    

    查詢出 gender 必須是 "M"并且 address 必須包含 “mill”,如果 lastname 里有 “Hines” 就最好并且會加額外相關性得分,但是 age 必須不能是 18 的所有文檔。

    7)、filter【結果過濾】

    并不是所有的查詢都需要產生相關性得分,特別是那些僅用于 “filtering”(過濾)的文檔。為了不計算相關性得分 ElasticSearch 會自動檢查場景并且優化查詢的執行。

    GET /bank/_search
    {
      "query": {
        "bool": {
          "filter": [
            {
              "range": {
                "age": {
                  "gte": 18,
                  "lte": 30
                }
              }
            }
          ]
        }
      }
    }
    
    GET /bank/_search
    {
      "query": {
        "bool": {
          "must": [
            {"match": {
              "gender": "M"
            }},
            {"match": {
              "address": "mill"
            }}
          ],
          "must_not": [
            {"match": {
              "age": "18"
            }}
          ],
          "should": [
            {"match": {
              "lastname": "Hines"
            }}
          ],
          "filter": [
            {
              "range": {
                "age": {
                  "gte": 18,
                  "lte": 30
                }
              }
            }
          ]
        }
      }
    }
    

    filter 不會計算相關性得分,會直接將不滿足 filter 的文檔給過濾掉。

    8)、term

    和 match 一樣,匹配某個屬性的值。全文檢索字段用 match,其他非 text 字段匹配用 term。

    GET /bank/_search
    {
      "query": {
        "term": {
          "age": "25"
        }
      }
    }
    
    GET /bank/_search
    {
      "query": {
        "match_phrase": {
          "address": "927 Bay"
        }
      }
    }
    
    GET /bank/_search
    {
      "query": {
        "match": {
          "address.keyword": "927 Bay"
        }
      }
    }
    

    非text(非文本)字段建議使用 term 進行匹配文本字段的全文檢索建議使用 match

    對于文本字段的匹配,“match_phrase” 與 “address.keyword” 不同的是整個 "address.keyword "的內容就是 “927 Bay” 的全部值,進行的是精確匹配;而 “match_phrase” 做的是短語匹配,意思是 address 文本里面包含一個完整短語 “927 Bay”

    9)、aggregations(執行聚合)

    聚合提供了從函數中分組和提取數據的能力,最簡單的聚合方法大致等于SQL GROUP BY 和 SQL 聚合函數。在 ElasticSearch 中,可以執行搜索返回 hits(命中結果),并且同時返回聚合結果,把一個響應中的所有 hits(命中結果)分隔開。我們就能夠執行查詢和多個聚合,并且在一次使用中得到各自的(任何一個的)返回結果,使用一次簡潔的 API 來避免網絡往返。

    • 搜索 address 中包含 mill 的所有人的年齡分布以及平均年齡,但不顯示這些人的詳情。
    GET /bank/_search
    {
      "query": {# 先查詢出來 address 中包含 mill 的所有文檔
        "match": {
          "address": "mill"
        }
      },
      "aggs": {# 執行聚合
        "ageAgg": {# 本次聚合的名字,方便展示在結果集中
          "terms": {# 聚合的類型【只看某個字段的信息】
            "field": "age",# 對哪個字段進行聚合
            "size": 10# 對聚合的結果作取幾條數據處理
          }
        },
        "ageAvg":{# 本次聚合的名字,方便展示在結果集中
          "avg": {# 聚合的類型 【取平均值】
            "field": "age"# 對哪個字段進行聚合
          }
        },
        "balanceAvg":{# 本次聚合的名字,方便展示在結果集中
          "avg": {# 聚合的類型 【取平均值】
            "field": "balance"# 對哪個字段進行聚合
          }
        }
      },
      "size": 0# 不顯示搜索數據
    }
    
    • 按照年齡聚合,并且請求這些年齡段的這些人的平均薪資

    先根據年齡聚合,再在這些年齡的聚合中套用聚合算出薪資平均值

    GET /bank/_search
    {
      "query": {
        "match_all": {}
      },
      "aggs": {
        "ageAgg": {
          "terms": {
            "field": "age",
            "size": 100
          },
          "aggs": {
            "balanceAvg": {
              "avg": {
                "field": "balance"
              }
            }
          }
        }
      }
    }
    
    • 查出所有年齡分布,并且這些年齡段中 M 的平均薪資和 F 的平均薪資以及這個年齡段的總體平均薪資
    GET /bank/_search
    {
      "query": {
        "match_all": {}
      },
      "aggs": {
        "ageAgg": {
          "terms": {
            "field": "age",
            "size": 100
          },
          "aggs": {
            "genderAgg": {
              "terms": {
                "field": "gender.keyword",
                "size": 10
              },
              "aggs": {
                "balanceAvg": {
                  "avg": {
                    "field": "balance"
                  }
                }
              }
            },
            "ageBalanceAvg":{
              "avg": {
                "field": "balance"
              }
            }
          }
        }
      }
    }
    

    3、Mapping【詳細參考

    1)、字段類型【詳細參考
    核心類型
    字符串(String)text, keyword
    數字類型(Numeric)long, integer, short, byte, double, float, half_float, scaled_float
    日期類型(Date)date
    布爾類型(Boolean)boolean
    二進制類型(Binary)binary
    復合類型
    數組類型(Array)Array 支持 不針對特定的類型
    對象類型(Object)object 用于 單JSON對象
    嵌套類型(Nested)nested 用于 JSON對象數組
    地理類型
    地理坐標(Geo-Points)geo_point 用于描述 經緯度坐標
    地理圖形(Geo-Shape)geo_shape 用于描述 復雜形狀,如多邊形
    特定類型
    IP類型ip 用于描述 ipv4 和 ipv6 地址
    補全類型(Completion)completion 提供自動完成提示
    令牌計數類型(Token count)token_count 用于 統計字符串中的詞條數量
    附件類型(Attachment)參考 mapper-attachments 插件,支持將附件如 Microsoft Office格式、
    Open Document格式、ePub、HTML等等索引為 attachment 數據類型
    抽取類型(Percolator)接受特定領域查詢語言(query-dsl)的查詢
    多字段
    通常用于為不同目的用不同的方法索引同一個字段。例如,string 字段可以映射為一個 text 字段用于全文檢索,同樣可以映射為一個 keyword 字段用于排序和聚合。另外,你可以使用 standard analyzer,english analyzer,french analyzer 來索引一個text字段。
    這就是 muti-fields 的目的。大多數的數據類型通過 fields 參數來支持 muti-fields。
    2)、映射

    Mapping(映射)

    Mapping 是用來定義一個文檔(document),以及它所包含的屬性(field)是如何存儲和索引的。比如,使用 mapping 來定義:

    • 哪些字符串屬性應該被看成全文本屬性(full text firlds);
    • 哪些屬性包含數字、日期或者地理位置;
    • 文檔中的所有屬性是否都能被索引( _all 配置);
    • 日期的格式;
    • 自定義映射規則來執行動態添加屬性
    查看 mapping 信息:
    GET /bank/_mapping
    
    3)、新版本改變
    ElasticSearch7 及以后版本移除了 type 概念
    • 關系型數據庫中兩個數據表示是獨立的,即使他們里面有相同名稱的列也不影響使用,但 ES 中不是這樣的。ElasticSearch 是基于 Lucene 開發的搜索引擎,而ES中不同 type 下名稱相同的 filed 最終在 Lucene 的處理方式是一樣的。

      • 兩個不同 type 下的兩個 user_name,在 ES 同一個索引下其實被認為是同一個 filed,必須在兩個不同的 type 中定義相同的 filed 映射,否則,不同 type 中的相同字段名稱就會在處理中出現沖突的情況,導致 Lucene 處理效率下降。

      • 移除 type 就是為了提高 ES 處理數據的效率。

    • ElasticSearch 7.X

      • URL 中的 type 參數為可選。比如,索引一個文檔不再要求具體提供文檔類型。
    • ElasticSearch 8.X

      • 不再支持 URL 中的 type 參數。
    • 解決:將索引從多類型遷移到單類型,每種類型文檔一個獨立索引;或者將已存在的索引下的類型數據,全部遷移到指定位置即可,詳見數據遷移。

    1、創建索引,并指定索引下每一個數據的類型,指定數據的映射規則
    PUT /my_index# 發送PUT請求,指定索引,在索引后不需要加type了
    {
      "mappings": {# "mappings" 創建映射規則
        "properties": {# "properties" 指明每一個屬性的映射類型
          "age":{"type": "integer"},# "屬性名":{【詳細規則:】"type": "指定什么類型"}
          "email":{"type": "keyword"},# "屬性名":{"type": "指定什么類型"}
          "name":{"type": "text"}# "屬性名":{"type": "指定什么類型"}
        }
      }
    }
    
    2、添加新的字段映射
    PUT /my_index/_mapping# 發送PUT請求,指定修改某個索引"index"下的映射"_mapping",僅限于添加新的字段
    {
      "properties": {# "properties" 指明每一個屬性的映射類型
        "employee-id": {# 定義新增加的屬性,為"employee-id"
          "type": "keyword", # 指定類型
          "index": false# 映射參數"index"用于控制該屬性能否被索引,能否被檢索到,默認為true可以被索引
        }
      }
    }
    
    3、更新映射

    對于已經存在的映射字段,不能通過上面兩個操作實現更新操作。更新必須通過創建新的索引并進行數據遷移。

    4、數據遷移

    先創建出一個正確映射,同時最好正確指定好每一個數據的類型,然后使用 “_reindex” 進行數據遷移

    創建步驟參考第一個創建索引并指定每一個數據類型操作,字段名要統一,可以先查看舊索引的 mapping 信息,然后復制 properties 屬性再進行字段屬性類型修改
    POST _reindex# 發送POST請求,進行"_reindex"索引下數據遷移操作
    {
      "source": {# 來源于哪個舊索引
        "index": "bank",# 舊索引的索引名
        "type": "account"# 如果是帶有type的,就寫上type名。沒有的話就可以不寫
      },
      "dest": {# 目標索引,新索引
        "index": "newbank"# 新索引的名字
      }
    }
    

    4、分詞

    ES有個分詞器 tokenizer 能接收一個字符流,將之分割為獨立的tokens(詞元,通常是獨立的單詞),然后輸出 tokens 流。

    同時ES提供了很多內置的分詞器,可以用來構建 custom analyzer(自定義分詞器)。

    1)、安裝ik分詞器

    注意:不要用默認 elasticsearch-plugin install xxx.zip 進行自動安裝。

    要進入 https://github.com/medcl/elasticsearch-analysis-ik/releases 對應ES版本安裝

    1. 進入 ES 容器內部 plugins 目錄
    2. docker exec -it 容器id /bin/bash
    3. wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.10.1/elasticsearch-analysis-ik-7.10.1.zip
    4. upzip 下載的文件
    5. rm -rf *.zip
    6. mv elasticsearch/ ik
    7. 可以確認是否安裝好了分詞器
    8. cd …/bin
    9. elasticsearch plugin list:即可列出系統的分詞器
    2)、測試分詞器
    POST _analyze
    {
      "analyzer": "ik_smart",
      "text": ["我是中國人"]
    }
    
    POST _analyze
    {
      "analyzer": "ik_max_word",# 找到最大的單詞組合
      "text": ["我是中國人"]
    }
    
    3)、自定義詞庫

    修改 /usr/share/elasticsearch/plugins/ik/config 中的 IKAnalyzer.cfg.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE properties SYSTEM "http://java./dtd/properties.dtd">
    <properties>
            <comment>IK Analyzer 擴展配置</comment>
            <!--用戶可以在這里配置自己的擴展字典 -->
            <entry key="ext_dict"></entry>
             <!--用戶可以在這里配置自己的擴展停止詞字典-->
            <entry key="ext_stopwords"></entry>
            <!--用戶可以在這里配置遠程擴展字典 -->
            <entry key="remote_ext_dict">http://192.168.56.10/es/fenci.txt</entry>
            <!--用戶可以在這里配置遠程擴展停止詞字典-->
            <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
    </properties>
    

    五、ElasticSearch-Rest-Client

    1、對比

    1)、9300:TCP
    • spring-data-elasticsearch:transport-api.jar
      • springboot版本不同,transport-api.jar 不同,不能適配 es 版本

      • 7.x 已經不建議使用,8 以后就要廢棄

    2)、9200:HTTP
    • JestClient:非官方,更新慢

    • RestTemplate:模擬發 HTTP 請求,ES 很多操作需要自己封裝,麻煩

    • HttpClient:同上

    • Elasticsearch-Rest-Client:官方 RestClient,封裝了 ES 操作,API 層次分明,上手簡單

    最終選擇 Elasticsearch-Rest-Client(elasticsearch-high-level-client)

    2、實例

    1)、導入依賴后編寫配置類
    /**
     * 1、導入依賴
     * 2、編寫配置,給容器中注入一個 RestHighLevelClient
     * 3、參照 API https://www./guide/en/elasticsearch/client/java-rest/7.x/java-rest-high.html
     */
    @Configuration
    public class MyElasticSearchConfig {
    
        public static final RequestOptions COMMON_OPTIONS;
        static {
            RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
    //        builder.addHeader("Authorization", "Bearer "   TOKEN);
    //        builder.setHttpAsyncResponseConsumerFactory(
    //                new HttpAsyncResponseConsumerFactory
    //                        .HeapBufferedResponseConsumerFactory(30 * 1024 * 1024 * 1024));
            COMMON_OPTIONS = builder.build();
        }
    
        @Bean
        public RestHighLevelClient esRestClient() {
            RestClientBuilder builder = null;
            builder = RestClient.builder(new HttpHost("IP", 9200, "http"));
            RestHighLevelClient client = new RestHighLevelClient(builder);
    //        RestHighLevelClient client = new RestHighLevelClient(
    //                RestClient.builder(
    //                        new HttpHost("IP", 9200, "http")));
            return client;
        }
    
    }
    
    2)、測試類
    @RunWith(SpringRunner.class)
    @SpringBootTest
    class MymallSearchApplicationTests {
    
        @Autowired
        private RestHighLevelClient client;
    
        /**
         *
         */
        @ToString
        @Data
        static class Account {
            private int account_number;
            private int balance;
            private String firstname;
            private String lastname;
            private int age;
            private String gender;
            private String address;
            private String employer;
            private String email;
            private String city;
            private String state;
    
        }
    
        /**
         *
         */
        @Test
        public void searchIndex() throws IOException {
            //1、創建檢索請求
            SearchRequest searchRequest = new SearchRequest();
            //指定索引
            searchRequest.indices("bank");
            //指定 DSL ,檢索條件
            // SearchSourceBuilder searchSourceBuilder 封裝的條件
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            //1.1)、構造檢索條件
            searchSourceBuilder.query(QueryBuilders.matchQuery("address", "mill"));
            //1.2)、按照年齡的值分布進行聚合
            TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age").size(10);
            searchSourceBuilder.aggregation(ageAgg);
            //1.3)、計算平均薪資
            AvgAggregationBuilder balanceAvg = AggregationBuilders.avg("balanceAvg").field("balance");
            searchSourceBuilder.aggregation(balanceAvg);
    
            System.out.println("檢索條件:"   searchSourceBuilder.toString());
    
            searchRequest.source(searchSourceBuilder);
    
            //2、執行檢索
            SearchResponse searchResponse = client.search(searchRequest, MymallElasticSearchConfig.COMMON_OPTIONS);
    
            //3、分析結果 searchResponse
            System.out.println(searchResponse.toString());
    //        Map map = JSON.parseObject(searchResponse.toString(), Map.class);
            //3.1)、獲取所有查到的數據
            SearchHits hits = searchResponse.getHits();
            SearchHit[] searchHits = hits.getHits();
            for (SearchHit hit : searchHits) {
                /**
                 * "_index": "bank",
                 * "_type": "account",
                 * "_id": "970",
                 * "_score": 5.4032025,
                 * "_source": {}
                 */
    //            hit.getIndex();hit.getType();hit.getId();
                String sourceAsString = hit.getSourceAsString();
                Account account = JSON.parseObject(sourceAsString, Account.class);
                System.out.println("account:"   account);
            }
    
            //3.2)、獲取這次檢索到的分析信息
            Aggregations aggregations = searchResponse.getAggregations();
    //        for (Aggregation aggregation : aggregations.asList()) {
    //            System.out.println("當前聚合:" aggregation.getName());
    //        }
            Terms ageAgg1 = aggregations.get("ageAgg");
            for (Terms.Bucket bucket : ageAgg1.getBuckets()) {
                String keyAsString = bucket.getKeyAsString();
                System.out.println("年齡:"   keyAsString       "==>"   bucket.getDocCount());
            }
    
            Avg balanceAvg1 = aggregations.get("balanceAvg");
            System.out.println("平均薪資:"   balanceAvg1.getValue());
    
        }
    
        /**
         * 測試存儲數據到 ES
         * 也可以進行更新操作
         */
        @Test
        public void indexData() throws IOException {
            IndexRequest indexRequest = new IndexRequest("users");
            indexRequest.id("1");//數據的id
    //        indexRequest.source("username","PrPrPr","age",22,"gender","女");
            User user = new User();
            user.setUserName("PrPrPr");
            user.setAge(23);
            user.setGender("女");
            String jsonString = JSON.toJSONString(user);
            indexRequest.source(jsonString, XContentType.JSON);//要保存的內容
    
            //執行操作
            IndexResponse index = client.index(indexRequest, MymallElasticSearchConfig.COMMON_OPTIONS);
    
            //提取有用的響應數據
            System.out.println(index);
        }
    }
    

    六、安裝 nginx

    • 隨便啟動一個 nginx 實例,只是為了復制出配置(如果沒有該鏡像,也會先下載鏡像后啟動容器實例)
    [root@localhost mydata]# mkdir nginx
    [root@localhost mydata]# ls
    elasticsearch  mysql  mysql8  nginx  redis
    [root@localhost mydata]# docker run -p 80:80 --name nginx -d nginx:1.19
    Unable to find image 'nginx:1.19' locally
    1.19: Pulling from library/nginx
    a076a628af6f: Already exists 
    0732ab25fa22: Pull complete 
    d7f36f6fe38f: Pull complete 
    f72584a26f32: Pull complete 
    7125e4df9063: Pull complete 
    Digest: sha256:10b8cc432d56da8b61b070f4c7d2543a9ed17c2b23010b43af434fd40e2ca4aa
    Status: Downloaded newer image for nginx:1.19
    227cc822c4679c2f6de23bbc6cdd4b27c7555214a959e31bc2aff0ef4c8df0c4
    
    • 將容器內的配置文件拷貝到當前目錄【別忘了命令后的點,并且 nginx 和點之間有個空格】
    [root@localhost mydata]# ll nginx/
    total 0
    [root@localhost mydata]# docker container cp nginx:/etc/nginx .
    [root@localhost mydata]# ll nginx/
    total 36
    drwxr-xr-x. 2 root root   26 Feb 27 16:39 conf.d
    -rw-r--r--. 1 root root 1007 Dec 15 13:59 fastcgi_params
    -rw-r--r--. 1 root root 2837 Dec 15 13:59 koi-utf
    -rw-r--r--. 1 root root 2223 Dec 15 13:59 koi-win
    -rw-r--r--. 1 root root 5231 Dec 15 13:59 mime.types
    lrwxrwxrwx. 1 root root   22 Dec 15 13:59 modules -> /usr/lib/nginx/modules
    -rw-r--r--. 1 root root  643 Dec 15 13:59 nginx.conf
    -rw-r--r--. 1 root root  636 Dec 15 13:59 scgi_params
    -rw-r--r--. 1 root root  664 Dec 15 13:59 uwsgi_params
    -rw-r--r--. 1 root root 3610 Dec 15 13:59 win-utf
    [root@localhost mydata]# docker stop nginx
    nginx
    [root@localhost mydata]# docker rm nginx
    nginx
    
    • 修改文件 nginx 名稱為 conf,并把這個 conf 文件夾移動到 /mydata/nginx 下
    [root@localhost mydata]# mv nginx conf
    [root@localhost mydata]# ls
    conf  elasticsearch  mysql  mysql8  redis
    [root@localhost mydata]# mkdir nginx
    [root@localhost mydata]# mv conf nginx/
    [root@localhost mydata]# ls
    elasticsearch  mysql  mysql8  nginx  redis
    
    • 創建新的 nginx,執行以下命令
    docker run -p 80:80 --name nginx -v /mydata/nginx/html:/usr/share/nginx/html -v /mydata/nginx/logs:/var/log/nginx -v /mydata/nginx/conf:/etc/nginx -d nginx:1.19
    
    來源:https://www./content-4-874951.html

      本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發現有害或侵權內容,請點擊一鍵舉報。
      轉藏 分享 獻花(0

      0條評論

      發表

      請遵守用戶 評論公約

      類似文章 更多

      主站蜘蛛池模板: 国产高清在线男人的天堂| 老少配老妇老熟女中文普通话| 国产精品自在拍首页视频| 又爽又黄无遮拦成人网站| 久久97人人超人人超碰超国产| 亚洲国产精品无码久久98| 国产成人亚洲日韩欧美| 94人妻少妇偷人精品| 色屁屁WWW影院免费观看入口| 日本高清色WWW在线安全| 午夜免费福利小电影| 国产一区二区三区美女 | 国产成人不卡一区二区| 国产精品免费看久久久| 国产成人啪精品午夜网站 | 又爽又黄又无遮掩的免费视频| 久久天天躁夜夜躁狠狠| 国厂精品114福利电影免费| 日产精品一卡2卡三卡四乱码| 午夜成人无码免费看网站| 六月丁香婷婷色狠狠久久 | 久久午夜无码鲁丝片| 人妻精品久久无码专区精东影业| 2020年最新国产精品正在播放 | 日本熟妇XXXX潮喷视频| 在线一区二区中文字幕| 亚洲精品无码日韩国产不卡av| 高潮潮喷奶水飞溅视频无码| 婷婷色香五月综合缴缴情香蕉 | 国模精品一区二区三区| 麻豆国产成人AV在线播放| 国产熟睡乱子伦视频在线播放| 国产欧美久久久精品影院| 精选国产av精选一区二区三区| 色噜噜亚洲男人的天堂| 亚洲男人第一无码av网站| 秋霞A级毛片在线看| 精品人妻二区中文字幕| 中文字幕人妻系列人妻有码 | 国产激情电影综合在线看| 色伦专区97中文字幕|