<input id="ohw05"></input>
  • <table id="ohw05"><menu id="ohw05"></menu></table>
  • <var id="ohw05"></var>
  • <code id="ohw05"><cite id="ohw05"></cite></code>
    <label id="ohw05"></label>
    <var id="ohw05"></var>
  • Elasticsearch核心技術(二):Elasticsearch入門

    本文從基本概念、基本CRUD操作、倒排索引原理、分詞等部分來初識Elasticsearch。

    2.1 基本概念

    Elasticsearch是面向文檔(Document)的,文檔是所有可搜索數據的最小單位;文檔會被序列化成Json格式,保存在Elasticsearch中,并且每個文檔都有一個唯一ID,可以通過Elasticsearch自動生成,也可以自己進行指定。對比MySQL,每行數據都有一個主鍵,這個主鍵可以使用MySQL自增主鍵,也可以通過雪花算法等方式生成然后進行自己設置。

    文檔的元數據,用于標注文檔的相關信息。例如:_index表示文檔所屬的索引名,_id表示文檔唯一ID,_score表示相關性打分,_source是文檔的原始Json數據等。

    索引(Index)是文檔的容器,是一類文檔的集合。對比MySQL,可以認為索引為一個數據表。

    Mapping用來定義字段名和類型,對比MySQL,每個表有表結構的定義,包括字段名稱,字段類型等。與關系型數據庫進行類比:

    RDBMS Elasticsearch
    Table Index
    Row Document
    Column Field
    Schema Mapping
    SQL DSL

    節點是一個Elasticsearch的實例,本質上是一個Java進程。節點按照角色可以劃分為主節點、數據節點、協調節點和預處理節點等。數據節點是保存數據的節點,協調節點負責接收Client的請求,將請求路由到到合適的節點,并將結果匯集到一起。
    節點分類

    集群是有多個節點組成的。

    分片分為主分片和副本,每個分片可以設置一定數量的副本。主分片用于解決數據的水平擴展問題,通過主分片可以將數據分布到集群內的所有節點上。副本是主分片的拷貝,用來解決數據高可用的問題,副本分片數可以動態調整,增加副本數,可以在一定程度上提高服務的可用性。當然副本可以提供查詢功能,分攤系統的讀負載。例如下圖中,分片數為3,副本數為1。

    因為主分片數設定之后無法修改,所以生產環境中分片的設定需要提前進行規劃。分片數量設置過小會導致后續無法增加節點實現水平擴展;而單個分片數據量太大,會導致數據重新分片耗時。分片數設置過大,會影響搜索結果的相關性打分,影響統計結果的準確性;而單個節點上有過多的分片,會導致資源浪費,同時會影響性能。

    2.2 基本CRUD操作與批量操作

    Elasticsearch對外提供RESTful API用于CRUD。使用RESTful API與Elasticsearch進行交互有兩種方式:curl命令行和Kibana DevTools。可以直接使用Kibana DevTool與Elasticsearch進行交互。

    2.2.1 索引操作

    1. 創建索引
      request: PUT /test_index
      response:
    { 
      "acknowledged" : true,
      "shards_acknowledged" : true,
      "index" : "test_index"
    } 
    
    1. 查看現有索引
      request:GET _cat/indices
      response:green open test_index GRXXECvrQjuNKRog7aDkPQ 1 1 2 3 28.9kb 14.4kb

    2. 刪除索引
      request:DELETE /test_index
      response:

    {
      "acknowledged" : true
    }
    

    2.2.2 文檔操作

    1. 指定id創建文檔

    request:

    PUT /test_index/_doc/1
    {
      "username":"Paul",
      "age":10
    }
    

    response:

    {
      "_index" : "test_index",
      "_type" : "_doc",
      "_id" : "1",
      "_version" : 1,
      "result" : "created",
      "_shards" : {
        "total" : 2,
        "successful" : 2,
        "failed" : 0
      },
      "_seq_no" : 0,
      "_primary_term" : 1
    }
    
    1. 不指定id創建文檔

    request:

    POST /test_index/_doc
    {
      "username":"Rose",
      "age":11
    }
    

    response:

    {
      "_index" : "test_index",
      "_type" : "_doc",
      "_id" : "soOv1HcB4Isa6tvVdQ9J",
      "_version" : 1,
      "result" : "created",
      "_shards" : {
        "total" : 2,
        "successful" : 2,
        "failed" : 0
      },
      "_seq_no" : 1,
      "_primary_term" : 1
    }
    
    1. 指定id查詢文檔

    request:GET /test_index/_doc/1

    response:

    {
      "_index" : "test_index",
      "_type" : "_doc",
      "_id" : "1",
      "_version" : 1,
      "_seq_no" : 0,
      "_primary_term" : 1,
      "found" : true,
      "_source" : {
        "username" : "Paul",
        "age" : 10
      }
    }
    
    1. 查詢所有文檔

    request:GET /test_index/_search

    response:

    {
      "took" : 2,
      "timed_out" : false,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 2,
          "relation" : "eq"
        },
        "max_score" : 1.0,
        "hits" : [
          {
            "_index" : "test_index",
            "_type" : "_doc",
            "_id" : "1",
            "_score" : 1.0,
            "_source" : {
              "username" : "Paul",
              "age" : 10
            }
          },
          {
            "_index" : "test_index",
            "_type" : "_doc",
            "_id" : "soOv1HcB4Isa6tvVdQ9J",
            "_score" : 1.0,
            "_source" : {
              "username" : "Rose",
              "age" : 11
            }
          }
        ]
      }
    }
    
    1. 更新文檔

    request:

    POST /test_index/_update/1
    {
      "doc": {
        "username": "Paul",
        "age": 20
      }
    }
    

    response:

    {
      "_index" : "test_index",
      "_type" : "_doc",
      "_id" : "1",
      "_version" : 2,
      "result" : "updated",
      "_shards" : {
        "total" : 2,
        "successful" : 2,
        "failed" : 0
      },
      "_seq_no" : 2,
      "_primary_term" : 1
    }
    
    1. 刪除文檔

    request:DELETE /test_index/_doc1

    2.2.3 批量操作

    批量操作可以減少網絡連接所產生的開銷,提高性能。

    • _bulk

    支持在一次API調用中,對不同的索引進行操作。

    bulk支持Index、Create、Update?Delete四種操作。

    請求中單條操作失敗,并不會影響其他操作,返回結果中包含每一條操作的執行結果。

    request:

    POST _bulk
    {"index":{"_index":"test_index", "_id":"1"}}
    {"username":"Smart", "age":22}
    {"delete":{"_index":"test_index", "_id":"2"}}
    

    response:

    {
      "took" : 95,
      "errors" : false,
      "items" : [
        {
          "index" : {
            "_index" : "test_index",
            "_type" : "_doc",
            "_id" : "1",
            "_version" : 5,
            "result" : "updated",
            "_shards" : {
              "total" : 2,
              "successful" : 2,
              "failed" : 0
            },
            "_seq_no" : 5,
            "_primary_term" : 1,
            "status" : 200
          }
        },
        {
          "delete" : {
            "_index" : "test_index",
            "_type" : "_doc",
            "_id" : "2",
            "_version" : 1,
            "result" : "not_found",
            "_shards" : {
              "total" : 2,
              "successful" : 2,
              "failed" : 0
            },
            "_seq_no" : 6,
            "_primary_term" : 1,
            "status" : 404
          }
        }
      ]
    }
    
    • 批量讀取mget

    request:

    GET _mget
    {
      "docs":[
        {
          "_index":"test_index",
          "_id":1
        },
        {
          "_index":"movies",
          "_id":1
        }]
    }
    

    response:

    {
      "docs" : [
        {
          "_index" : "test_index",
          "_type" : "_doc",
          "_id" : "1",
          "_version" : 2,
          "_seq_no" : 2,
          "_primary_term" : 1,
          "found" : true,
          "_source" : {
            "username" : "Paul",
            "age" : 20
          }
        },
        {
          "_index" : "movies",
          "_type" : "_doc",
          "_id" : "1",
          "_version" : 1,
          "_seq_no" : 6,
          "_primary_term" : 1,
          "found" : true,
          "_source" : {
            "id" : "1",
            "title" : "Toy Story",
            "year" : 1995,
            "genre" : [
              "Adventure",
              "Animation",
              "Children",
              "Comedy",
              "Fantasy"
            ],
            "@version" : "1"
          }
        }
      ]
    }
    
    • 批量查詢msearch

    request:

    POST test_index/_msearch
    {}
    {"query":{"match_all":{}},"size":1}
    {"index":"kibana_sample_data_flights"}
    {"query":{"match_all":{}},"size":2}
    

    response:

    {
      "took" : 4,
      "responses" : [
        {
          "took" : 2,
          "timed_out" : false,
          "_shards" : {
            "total" : 1,
            "successful" : 1,
            "skipped" : 0,
            "failed" : 0
          },
          "hits" : {
            "total" : {
              "value" : 2,
              "relation" : "eq"
            },
            "max_score" : 1.0,
            "hits" : [
              {
                "_index" : "test_index",
                "_type" : "_doc",
                "_id" : "soOv1HcB4Isa6tvVdQ9J",
                "_score" : 1.0,
                "_source" : {
                  "username" : "Rose",
                  "age" : 11
                }
              }
            ]
          },
          "status" : 200
        },
        {
          "took" : 4,
          "timed_out" : false,
          "_shards" : {
            "total" : 1,
            "successful" : 1,
            "skipped" : 0,
            "failed" : 0
          },
          "hits" : {
            "total" : {
              "value" : 10000,
              "relation" : "gte"
            },
            "max_score" : 1.0,
            "hits" : [
              {
                "_index" : "kibana_sample_data_flights",
                "_type" : "_doc",
                "_id" : "iTmvUXcBNxIYppLoFWwg",
                "_score" : 1.0,
                "_source" : {
                  "FlightNum" : "R3J7URU",
                  "DestCountry" : "US",
                  "OriginWeather" : "Hail",
                  "OriginCityName" : "Moscow",
                  "AvgTicketPrice" : 1172.5681640799792,
                  "DistanceMiles" : 5149.888524287689,
                  "FlightDelay" : false,
                  "DestWeather" : "Rain",
                  "Dest" : "Spokane International Airport",
                  "FlightDelayType" : "No Delay",
                  "OriginCountry" : "RU",
                  "dayOfWeek" : 6,
                  "DistanceKilometers" : 8287.942197231247,
                  "timestamp" : "2021-02-14T10:59:03",
                  "DestLocation" : {
                    "lat" : "47.61989975",
                    "lon" : "-117.5339966"
                  },
                  "DestAirportID" : "GEG",
                  "Carrier" : "ES-Air",
                  "Cancelled" : false,
                  "FlightTimeMin" : 753.4492906573861,
                  "Origin" : "Sheremetyevo International Airport",
                  "OriginLocation" : {
                    "lat" : "55.972599",
                    "lon" : "37.4146"
                  },
                  "DestRegion" : "US-WA",
                  "OriginAirportID" : "SVO",
                  "OriginRegion" : "RU-MOS",
                  "DestCityName" : "Spokane",
                  "FlightTimeHour" : 12.557488177623101,
                  "FlightDelayMin" : 0
                }
              },
              {
                "_index" : "kibana_sample_data_flights",
                "_type" : "_doc",
                "_id" : "ijmvUXcBNxIYppLoFWwg",
                "_score" : 1.0,
                "_source" : {
                  "FlightNum" : "OE9TTXI",
                  "DestCountry" : "GB",
                  "OriginWeather" : "Sunny",
                  "OriginCityName" : "Guangzhou",
                  "AvgTicketPrice" : 834.6361636829536,
                  "DistanceMiles" : 5911.063226254684,
                  "FlightDelay" : false,
                  "DestWeather" : "Thunder & Lightning",
                  "Dest" : "London Heathrow Airport",
                  "FlightDelayType" : "No Delay",
                  "OriginCountry" : "CN",
                  "dayOfWeek" : 6,
                  "DistanceKilometers" : 9512.93413679362,
                  "timestamp" : "2021-02-14T08:13:00",
                  "DestLocation" : {
                    "lat" : "51.4706",
                    "lon" : "-0.461941"
                  },
                  "DestAirportID" : "LHR",
                  "Carrier" : "JetBeats",
                  "Cancelled" : true,
                  "FlightTimeMin" : 500.68074404176946,
                  "Origin" : "Guangzhou Baiyun International Airport",
                  "OriginLocation" : {
                    "lat" : "23.39240074",
                    "lon" : "113.2990036"
                  },
                  "DestRegion" : "GB-ENG",
                  "OriginAirportID" : "CAN",
                  "OriginRegion" : "SE-BD",
                  "DestCityName" : "London",
                  "FlightTimeHour" : 8.344679067362824,
                  "FlightDelayMin" : 0
                }
              }
            ]
          },
          "status" : 200
        }
      ]
    }
    

    2.3 倒排索引

    2.3.1 正排索引與倒排索引

    什么是正排索引?正排索引指的是從文檔Id到文檔內容、單詞的關聯關系。例如每本書的目錄,通過目錄可以很快找到某個標題的具體內容在書中的那一頁。

    什么是倒排索引?倒排索引指的文檔內容或者單詞到文檔Id的關聯關系。還是以書的例子,倒排索引指的是從具體內容到文章標題的索引。

    知乎上面有人舉了一個形象的例子。比如說考我們一首詩,給一首詩的名字,通常大家都可以背下來詩的內容。那為什么“飛花令”的時候我們想不起來詩句呢?因為我們的大腦中沒有建立從詩句中某個字到詩名的倒排索引,假如說建立了這樣的倒排索引,我們也可以像中國詩詞大會的選手一樣飛來飛去。

    文檔ID 文檔內容
    1 Elasticsearch是最流行的搜索引擎
    2 Java是世界上最好的語言
    3 Google是全球最大的搜索引擎
    單詞 文檔ID列表
    elasticsearch 1
    流行 1
    搜索引擎 1,3
    java 2
    世界 2
    最好 2
    語言 2
    google 3
    全球 3
    最大 3

    Elasticsearch存儲的是一個json格式的文檔,其中包含多個字段,每個字段都會有自己的倒排索引。

    那倒排索引是如何產生的呢?是文檔內容分詞之后和文檔ID進行關聯。

    2.4 分詞

    分詞是指將連續的字符串按照一定的規則重新切分成為單詞(term or token)的過程,在ES里面叫做Analysis。

    2.4.1 ES分詞器組成和自帶分詞器

    Analyzer是ES中專門處理分詞的組件,組成如下:

    • Character Filters:針對原始文本進行處理,比如去除HTML特殊標識符等
    • Tokenizer:將原始文本按照一定規則切分成為單詞
    • Token Filters:針對Tokenizer處理的單詞進行再加工,比如轉小寫、刪除停用詞或者新增同義詞等處理

    其工作過程如圖所示:

    Elasticsearch內置分詞器

    分詞器 說明
    Standard Analyzer 默認分詞器,按詞切分,小寫處理,停用詞處理默認關閉
    Simple Analyzer 按照非字母切分,非字母的都被去除,小寫處理
    Stop Analyzer 小寫處理,停用詞過濾
    Whitespace Analyzer 按照空格切分,不轉小寫
    Keyword Analyzer 不分詞,直接將輸入內容進行輸出
    Pattern Analyzer 正則表達式,默認\W+(非字母符號分割)
    Language 提供30多種常見語言的分詞器
    Customer Analyzer 自定義分詞器

    測試一下:

    • 直接指定Analyzer進行測試
    GET /_analyze
    {
      "analyzer": "standard",
      "text": [
        "Hello World, Hello Elasticsearch"
      ]
    }
    
    • 指定索引的字段進行測試
    POST /movies/_analyze
    {
      "field": "title",
      "text": [
        "Hello World, Hello Elasticsearch"
      ]
    }
    
    • 自定義分詞器進行測試
    POST /_analyze
    {
      "tokenizer": "standard",
      "filter": [
        "lowercase"
      ],
      "text": [
        "Hello World, Hello Elasticsearch"
      ]
    }
    

    2.4.2 Analyze API使用

    ES提供一個測試分詞的API接口,方便驗證分詞效果。_analyze

    可以直接指定analyzer進行測試

    可以直接指定索引中的字段進行測試:GET test_index/_analyze

    可以自定義分詞器進行測試

    至此,學習了基本API的使用、批量操作、倒排索引原理和分詞等概念,對ELasticsearch有了初步的認識。

    posted @ 2021-08-19 23:16  James_Shangguan  閱讀(1331)  評論(0編輯  收藏  舉報
    国产美女a做受大片观看