1. 程式人生 > 實用技巧 >POJ 2976 (01分數規劃)

POJ 2976 (01分數規劃)

目錄

介紹

Elasticsearch是什麼

elasticsearch是一個基於Lucene的分散式搜尋和引擎

elasticsearch是一個開源的高擴充套件的分散式全文搜尋引擎,它可以近乎實時的儲存、檢索資料;本身擴充套件性很好,可以擴充套件到上擺臺伺服器,處理PB級別的資料

Java開發,遵循Apache開源協議

使用Lucene作為其核心來實現所有的索引和搜尋功能,但是它的目的是通過簡單的RESTFUL API來隱藏Lucene的複雜性,使得全文檢索變得簡單

Lucene與Elasticearch關係

1 Lucne只是一個庫,想要使用它,你必須使用java來作為開發語言並將其直接集塵到你的應用中,更糟糕的是,Lucene非常複雜,你需要深入連線檢索的相關知識來理解它是如何工作的

2 Elasticsearch也使用java開發並使用Lucene作為其核心來實現所有的索引和搜尋的功能,但是他的目的是通過簡單的RESTFUL API來隱藏Lucene的複雜性,從而讓全文搜尋變得簡單

Elasticsearch vs solr

1)Solr是Apache Lucene專案的開源企業搜尋平臺。其主要功能包括全文檢索、命中標示、分面搜尋、動態聚類、資料庫整合,以及富文字(如Word、PDF)的處理。

2)Solr是高度可擴充套件的,並提供了分散式搜尋和索引複製。Solr是最流行的企業級搜尋引擎,Solr4 還增加了NoSQL支援。

3)Solr是用Java編寫、執行在Servlet容器(如 Apache Tomcat 或Jetty)的一個獨立的全文搜尋伺服器。 Solr採用了 Lucene Java 搜尋庫為核心的全文索引和搜尋,並具有類似REST的HTTP/XML和JSON的API。

4)Solr強大的外部配置功能使得無需進行Java編碼,便可對 其進行調整以適應多種型別的應用程式。Solr有一個外掛架構,以支援更多的高階定製

Elasticsearch 與 Solr 的比較總結

1. 二者安裝都很簡單
2. Solr 利用 Zookeeper 進行分散式管理,而 Elasticsearch 自身帶有分散式協調管理功能
3. Solr 支援更多格式的資料,而 Elasticsearch 僅支援json檔案格式
4. Solr 官方提供的功能更多,而 Elasticsearch 本身更注重於核心功能,高階功能多有第三方外掛提供
5. Solr 在傳統的搜尋應用中表現好於 Elasticsearch,但在處理實時搜尋應用時效率明顯低於 Elasticsearch
6. Solr 是傳統搜尋應用的有力解決方案,但 Elasticsearch 更適用於新興的實時搜尋應用

Elasticsearch核心概念

Cluster:叢集

ES可以作為一個獨立的單個搜尋伺服器。不過,為了處理大型資料集,實現容錯和高可用性,ES可以執行在許多互相合作的伺服器上。這些伺服器的集合稱為叢集。

Node:節點

形成叢集的每個伺服器稱為節點

Shard:分片

當有大量的文件時,由於記憶體的限制、磁碟處理能力不足、無法足夠快的響應客戶端的請求等,一個節點可能不夠。這種情況下,資料可以分為較小的分片。每個分片放到不同的伺服器上。
當你查詢的索引分佈在多個分片上時,ES會把查詢傳送給每個相關的分片,並將結果組合在一起,而應用程式並不知道分片的存在。即:這個過程對使用者來說是透明的。

Replia:副本

為提高查詢吞吐量或實現高可用性,可以使用分片副本。
副本是一個分片的精確複製,每個分片可以有零個或多個副本。ES中可以有許多相同的分片,其中之一被選擇更改索引操作,這種特殊的分片稱為主分片。
當主分片丟失時,如:該分片所在的資料不可用時,叢集將副本提升為新的主分片。

全文檢索

全文檢索就是對一篇文章進行索引,可以根據關鍵字搜尋,類似於mysql裡的like語句。
全文索引就是把內容根據詞的意義進行分詞,然後分別建立索引,例如”今日是週日我們出去玩” 可能會被分詞成:“今天“,”週日“,“我們“,”出去玩“ 等token,這樣當你搜索“週日” 或者 “出去玩” 都會把這句搜出來。

與關係型資料庫MySql對比

1)關係型資料庫中的資料庫(DataBase),等價於ES中的索引(Index)
2)一個數據庫下面有N張表(Table),等價於1個索引Index下面有N多型別(Type),
3)一個數據庫表(Table)下的資料由多行(ROW)多列(column,屬性)組成,等價於1個Type由多個文件(Document)和多Field組成。
4)在一個關係型資料庫裡面,schema定義了表、每個表的欄位,還有表和欄位之間的關係。 與之對應的,在ES中:Mapping定義索引下的Type的欄位處理規則,即索引如何建立、索引型別、是否儲存原始索引JSON文件、是否壓縮原始JSON文件、是否需要分詞處理、如何進行分詞處理等。
5)在資料庫中的增insert、刪delete、改update、查search操作等價於ES中的增PUT/POST、刪Delete、改_update、查GET.1.7

ES邏輯設計(文件-->型別-->索引)

一個索引型別中,包含多個文件,比如說文件1,文件2。
當我們索引一篇文件時,可以通過這樣的順序找到它:索引型別文件ID,通過這個組合我們就能索引到某個具體的文件。
注意:ID不必是整數,實際上它是個字串。

文件

之前說elasticsearch是面向文件的,那麼就意味著索引和搜尋資料的最小單位是文件,elasticsearch中,文件有幾個重要屬性:

  • 自我包含,一篇文件同時包含欄位和對應的值,也就是同時包含key:value
  • 可以是層次型的,一個文件中包含自文件,複雜的邏輯實體就是這麼來的
  • 靈活的結構,文件不依賴預先定義的模式,我們知道關係型資料庫中,要提前定義欄位才能使用,在elasticsearch中,對於欄位是非常靈活的,有時候,我們可以忽略該欄位,或者動態的新增一個新的欄位。
  • 文件是無模式的,也就是說,欄位對應值的型別可以是不限型別的。

儘管我們可以隨意的新增或者忽略某個欄位,但是,每個欄位的型別非常重要,比如一個年齡欄位型別,可以是字串也可以是整型。因為elasticsearch會儲存欄位和型別之間的對映及其他的設定。這種對映具體到每個對映的每種型別(詳見擴充套件閱讀:17-擴充套件閱讀-刪除對映型別.md),這也是為什麼在elasticsearch中,型別有時候也稱為對映型別。

型別

型別是文件的邏輯容器,就像關係型資料庫一樣,表格是行的容器。
型別中對於欄位的定義稱為對映,比如name對映為字串型別。
我們說文件是無模式的,它們不需要擁有對映中所定義的所有欄位,比如新增一個欄位,那麼elasticsearch是怎麼做的呢?elasticsearch會自動的將新欄位加入對映,但是這個欄位的不確定它是什麼型別,elasticsearch就開始猜,如果這個值是18,那麼elasticsearch會認為它是整型。
但是elasticsearch也可能猜不對,所以最安全的方式就是提前定義好所需要的對映,這點跟關係型資料庫殊途同歸了,先定義好欄位,然後再使用,別整什麼么蛾子。後面在討論更多關於對映的東西。

索引

索引是對映型別的容器,elasticsearch中的索引是一個非常大的文件集合。索引儲存了對映型別的欄位和其他設定。然後它們被儲存到了各個分片上了。

ES物理設計

一個叢集包含至少一個節點,而一個節點就是一個elasticsearch程序。節點內可以有多個索引。
預設的,如果你建立一個索引,那麼這個索引將會有5個分片(primary shard,又稱主分片)構成,而每個分片又有一個副本(replica shard,又稱複製分片),這樣,就有了10個分片。
那麼這個索引是如何儲存在叢集中的呢?
圖中有3個節點的叢集,可以看到主分片和對應的複製分片都不會在同一個節點內,這樣有利於某個節點掛掉了,資料也不至於丟失。
實際上,一個分片是一個Lucene索引,一個包含倒排索引的檔案目錄,倒排索引的結構使得elasticsearch在不掃描全部文件的情況下,就能告訴你哪些文件包含特定的關鍵字

ELK是什麼

ELK=elasticsearch+Logstash+kibana
elasticsearch:後臺分散式儲存以及全文檢索
logstash: 日誌加工、“搬運工”
kibana:資料視覺化展示。
ELK架構為資料分散式儲存、視覺化查詢和日誌解析建立了一個功能強大的管理鏈。 三者相互配合,取長補短,共同完成分散式大資料處理工作。

Elasticsearch特點和優勢

1)分散式實時檔案儲存,可將每一個欄位存入索引,使其可以被檢索到。
2)實時分析的分散式搜尋引擎。
分散式:索引分拆成多個分片,每個分片可有零個或多個副本。叢集中的每個資料節點都可承載一個或多個分片,並且協調和處理各種操作;
負載再平衡和路由在大多數情況下自動完成。
3)可以擴充套件到上百臺伺服器,處理PB級別的結構化或非結構化資料。也可以執行在單臺PC上(已測試)
4)支援外掛機制,分詞外掛、同步外掛、Hadoop外掛、視覺化外掛等。

為什麼使用Elasticsearch

國內外優秀案例

1) 2013年初,GitHub拋棄了Solr,採取ElasticSearch 來做PB級的搜尋。 “GitHub使用ElasticSearch搜尋20TB的資料,包括13億檔案和1300億行程式碼”。

2)維基百科:啟動以elasticsearch為基礎的核心搜尋架構。
3)SoundCloud:“SoundCloud使用ElasticSearch為1.8億使用者提供即時而精準的音樂搜尋服務”。
4)百度:百度目前廣泛使用ElasticSearch作為文字資料分析,採集百度所有伺服器上的各類指標資料及使用者自定義資料,通過對各種資料進行多維分析展示,輔助定位分析例項異常或業務層面異常。目前覆蓋百度內部20多個業務線(包括casio、雲分析、網盟、預測、文庫、直達號、錢包、風控等),單叢集最大100臺機器,200個ES節點,每天匯入30TB+資料。

5)新浪ES 如何分析處理32億條實時日誌
6)阿里ES 構建挖財自己的日誌採集和分析體系
7)有贊ES 業務日誌處理

我們的業務場景

實際專案開發實戰中,幾乎每個系統都會有一個搜尋的功能,當搜尋做到一定程度時,維護和擴充套件起來難度就會慢慢變大,所以很多公司都會把搜尋單獨獨立出一個模組,用ElasticSearch等來實現。

近年ElasticSearch發展迅猛,已經超越了其最初的純搜尋引擎的角色,現在已經增加了資料聚合分析(aggregation)和視覺化的特性,如果你有數百萬的文件需要通過關鍵詞進行定位時,ElasticSearch肯定是最佳選擇。當然,如果你的文件是JSON的,你也可以把ElasticSearch當作一種“NoSQL資料庫”, 應用ElasticSearch資料聚合分析(aggregation)的特性,針對資料進行多維度的分析。

嘗試使用ES來替代傳統的NoSQL,它的橫向擴充套件機制太方便了

應用場景:

1)新系統開發嘗試使用ES作為儲存和檢索伺服器;
2)現有系統升級需要支援全文檢索服務,需要使用ES

Elasticsearch索引到底能處理多大資料

單一索引的極限取決於儲存索引的硬體、索引的設計、如何處理資料以及你為索引備份了多少副本。

通常來說,一個Lucene索引(也就是一個elasticsearch分片,一個es索引預設5個分片)不能處理多於21億篇文件,或者多於2740億的唯一詞條。但達到這個極限之前,我們可能就沒有足夠的磁碟空間了!
當然,一個分片如何很大的話,讀寫效能將會變得非常差

ElasticSearch安裝

安裝JDK環境

因為ElasticSearch使用Java語言編寫的,所以必須安裝JDK的環境,並且是JDK1.8以上,具體步驟百度

檢視Java版本

java -version

官網下載最新版本

下載地址[https://www.elastic.co/cn/downloads/elasticsearch]

下載其他版本

直接點選https://www.elastic.co/cn/downloads/past-releases#elasticsearch

下載完成,啟動

解壓檔案,切換到解壓檔案路徑下,執行

cd elasticsearch-<version> #切換到路徑下

./bin/elasticsearch  #啟動es

#如果你想把 Elasticsearch 作為一個守護程序在後臺執行,那麼可以在後面新增引數 -d 。

#如果你是在 Windows 上面執行 Elasticseach,你應該執行 bin\elasticsearch.bat 而不是 bin\elasticsearch

測試啟動是否成功

在瀏覽器輸入以下地址:http://127.0.0.1:9200/

即可看到如下內容:

{
  "name" : "lqzMacBook.local",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "G1DFg-u6QdGFvz8Z-XMZqQ",
  "version" : {
    "number" : "7.5.0",
    "build_flavor" : "default",
    "build_type" : "tar",
    "build_hash" : "e9ccaed468e2fac2275a3761849cbee64b39519f",
    "build_date" : "2019-11-26T01:06:52.518245Z",
    "build_snapshot" : false,
    "lucene_version" : "8.3.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

關閉ES

#檢視程序
ps -ef | grep elastic

#幹掉程序
kill -9 2382(程序號)

#以守護程序方式啟動es
elasticsearch -d

ElascticSearch外掛介紹

es外掛是一種增強Elasticsearch核心功能的途徑。它們可以為es新增自定義對映型別、自定義分詞器、原生指令碼、自伸縮等等擴充套件功能。

es外掛包含JAR檔案,也可能包含指令碼和配置檔案,並且必須在叢集中的每個節點上安裝。安裝之後,需要重啟叢集中的每個節點才能使外掛生效。
es外掛包含核心外掛和第三方外掛兩種

核心外掛

核心外掛是elasticsearch專案提供的官方外掛,都是開源專案。這些外掛會跟著elasticsearch版本升級進行升級,總能匹配到對應版本的elasticsearch,這些外掛是有官方團隊和社群成員共同開發的。

官方外掛地址: https://github.com/elastic/elasticsearch/tree/master/plugins

第三方外掛

​ 第三方外掛是有開發者或者第三方組織自主開發便於擴充套件elasticsearch功能,它們擁有自己的許可協議,在使用它們之前需要清除外掛的使用協議,不一定隨著elasticsearch版本升級, 所以使用者自行辨別外掛和es的相容性。

外掛安裝

elasticsearch的外掛安裝方式還是很方便易用的。

它包含了命令列和離線安裝幾種方式。

它包含了命令列,url,離線安裝三種方式。

核心外掛隨便選擇一種方式安裝均可,第三方外掛建議使用離線安裝方式
第一種:命令列

bin/elasticsearch-plugin install [plugin_name]
# bin/elasticsearch-plugin install analysis-smartcn  安裝中文分詞器

第二種:url安裝

bin/elasticsearch-plugin install [url]
#bin/elasticsearch-plugin install https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-smartcn/analysis-smartcn-6.4.0.zip

第三種:離線安裝

#https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-smartcn/analysis-smartcn-6.4.0.zip
#點選下載analysis-smartcn離線包
#將離線包解壓到ElasticSearch 安裝目錄下的 plugins 目錄下
#重啟es。新裝外掛必須要重啟es

注意:外掛的版本要與 ElasticSearch 版本要一致

Kibana安裝(postman)

1 客戶端:瀏覽器,postman,kibana,elasticsearch-head(沒有桌面版客戶端)

2 官方提供的
	-Kibana 是一款開源的資料分析和視覺化平臺
    -Kibana一定要跟es版本對應,咱們用的都是7.5.0

3 解壓,就可以執行

4 連線es,需要配置
	-修改kibana配置
    # kibana監聽的埠和地址
    server.port: 5601
    server.host: "127.0.0.1"
    server.name: lqz
    # 連線哪個es
    elasticsearch.hosts: ["http://localhost:9200/"]

elasticsearch-head安裝

1 第三方開發的一個es客戶端(nodjs開發的,裝node環境)

2 下載,解壓

3 cd elasticsearch-head目錄下, npm install  安裝依賴

4 npm run serve 跑起來

5 會出現跨域,es目錄下config下elasticsearch.yml新增es配置
    http.cors.enabled: true
    http.cors.allow-origin: "*"

6 瀏覽器輸入
	http://localhost:9100/

es安裝官方,第三方外掛

# 三種安裝方式
# 推薦用第三種
 **第一種:命令列**
bin/elasticsearch-plugin install [plugin_name]
# bin/elasticsearch-plugin install analysis-smartcn  安裝中文分詞器

**第二種:url安裝**

bin/elasticsearch-plugin install [url]
#bin/elasticsearch-plugin install https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-smartcn/analysis-smartcn-6.4.0.zip

**第三種:離線安裝**
#https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-smartcn/analysis-smartcn-6.4.0.zip
#點選下載analysis-smartcn離線包
#將離線包解壓到ElasticSearch 安裝目錄下的 plugins 目錄下
#重啟es。新裝外掛必須要重啟es
​```

**注意:外掛的版本要與 ElasticSearch 版本要一致**

倒排索引

1 倒排索引:對文章進行分詞,對每個詞建立索引,由於這樣建,會出現索引爆炸,索引跟標題建關係,標題再跟文章建索引,如下:
	分詞---文章建立索引                             |

| 今天(索引)    | (文章1,<2,10>,2) (文章3,<8>,1)       |
| 星期天(索引) | (文章2,<12,25,100>,3)                 |
| 出去玩(索引) | (文章5,<11,24,89>,3)(文章1,<8,19>,2) |

今天出現在哪個文章,出現的位置和出現的次數

索引操作(資料庫)

1 新建索引
PUT lqz2
{
  "settings": {
    "index":{
      "number_of_shards":5,
      "number_of_replicas":1
    }
  }
}

# 新建索引
PUT lqz2
{
  "settings": {
    "index":{
      "number_of_shards":5,
      "number_of_replicas":1
    }
  }
}
PUT lqz


# 檢視索引
GET lqz2/_settings
GET lqz/_settings
GET _all/_settings

GET lqz,lqz2/_settings
GET _settings


# 修改索引(一般不太用,只能用來修改副本數量)
#修改索引副本數量為2  分片的數量一開始就要定好
# 副本數量可以改(有可能會出錯)
PUT lqz/_settings
{
  "number_of_replicas": 2
}

PUT  _all/_settings
{
"index": {
  "blocks": {
    "read_only_allow_delete": false
    }
  }
}



# 刪除索引
DELETE lqz


對映管理(型別)(表)

#1  在Elasticsearch 6.0.0或更高版本中建立的索引只包含一個mapping type。 在5.x中使用multiple mapping types建立的索引將繼續像以前一樣在Elasticsearch 6.x中執行。 Mapping types將在Elasticsearch 7.0.0中完全刪除



##索引如果不建立,只有插入文件,會自動建立

# 建立對映(型別,表)
PUT books
{
  "mappings": {
    "properties":{
      "title":{
        "type":"text",
        "analyzer": "ik_max_word"
      },
      "price":{
        "type":"integer"
      },
      "addr":{
        "type":"keyword"
      },
      "company":{
        "properties":{
          "name":{"type":"text"},
          "company_addr":{"type":"text"},
          "employee_count":{"type":"integer"}
        }
      },
      "publish_date":{"type":"date","format":"yyy-MM-dd"}
      
    }
    
  }
}



###檢視對映
GET lqz/_mapping
GET _all/_mapping


# 特殊說明索引對映都不存在,也可以插入文件
PUT lqz1/_doc/1
{
  "title":"白雪公主和十個小矮人",
  "price":"99",
  "addr":"黑暗森裡",
  "publish_date":"2018-05-19",
  "name":"lqz"
}
# 檢視索引
GET lqz/_settings
#檢視對映
GET lqz/_mapping

文件基本增刪查改(一行一行資料)

# 1 插入文件
PUT books/_doc/1
{
  "title":"大頭兒子小偷爸爸",
  "price":100,  
  "addr":"北京天安門",
  "company":{
    "name":"我愛北京天安門",
    "company_addr":"我的家在東北松花江傻姑娘",
    "employee_count":10
  },
  "publish_date":"2019-08-19"
}

PUT books/_doc/2
{
  "title":"白雪公主和十個小矮人",
  "price":"99", #寫字串會自動轉換
  "addr":"黑暗森裡",
  "publish_date":"2018-05-19"
}

PUT books/_doc/3
{
  "title":"白雪公主和十個小矮人",
  "price":"99", #寫字串會自動轉換
  "addr":"黑暗森裡",
  "publish_date":"2018-05-19",
   "name":"lqz"
}



## 查詢文件
GET lqz/_doc/1

## 修改文件兩種方式
# 第一種
PUT lqz/_doc/1
{
  "name":"顧老二",
  "age":30,
  "from": "gu",
  "desc": "面板黑、武器長、性格直",
  "tags": ["黑", "長", "直"]
}
# 第二種(區域性修改)
POST lqz/_doc/1/_update
{
  "doc": {
    "desc": "面板很safasdfsda黃,武器很長,性格很直",
    "tags": ["很黃","很長", "很直"]
  }
}



## 刪除文件
DELETE lqz/_doc/4

文件查詢

###查詢字串
# 查詢from欄位是gu的所有人
GET lqz/_doc/_search?q=from:gu
# 查詢age是22的人
GET lqz/_doc/_search?q=age:22

GET lqz/_doc/_search?q=desc:不知道
    
    
    
###結構化查詢

GET lqz/_doc/_search
{
  "query": {
    "match": {
      "from": "gu"
    }
  }
}

GET lqz/_doc/_search
{
  "query": {
    "match": {
      "from":"gu"
    }
  }
}

模糊查詢

match_all:查詢所有
match_phrase:短語查詢

GET t1/doc/_search
{
  "query": {
    "match_phrase": {
      "title": {
        "query": "中國世界",
        "slop": 2  # 中國和世界之間最多間隔2個字元
      }
    }
  }
}

文件查詢操作

match和term查詢

# 並且和或者的條件
#並且
GET t3/doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "title": "beautiful"
          }
        },
        {
          "match": {
            "desc": "beautiful"
          }
        }
      ]
    }
  }
}

#或者
GET t3/doc/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "title": "beautiful"
          }
        },
        {
          "match": {
            "desc": "beautiful"
          }
        }
      ]
    }
  }
}



# match,term和terms的區別
	-match查的短語會分詞
    GET w10/_doc/_search
        {
          "query": {
            "match": {
              "t1": "Beautiful girl!"
            }
          }
        }
    -term查的不會分詞
    GET w10/_doc/_search
            {
          "query": {
            "term": {
              "t1": "girl"
            }
          }
        }
    -terms由於部分詞,想查多個,terms
        GET w10/_doc/_search
        {
          "query": {
            "terms": {
              "t1": ["beautiful", "sexy"]
            }
          }
        }
        
        
        
# pymysql   原生操作,查出字典
# orm       orm直接轉成物件

排序查詢

##### 不是所有欄位都支援排序,只有數字型別,字串不支援

GET lqz/_doc/_search
{
  "query": {
    "match": {
      "from": "gu"
    }
  }
}

#降序
GET lqz/_doc/_search
{
  "query": {
    "match": {
      "from": "gu"
    }
  },
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ]
}

## 升序
GET lqz/_doc/_search
{
  "query": {
    "match": {
      "from": "gu"
    }
  },
  "sort": [
    {
      "age": {
        "order": "asc"
      }
    }
  ]
}


GET lqz/_doc/_search
{
  "query": {
    "match_all": {
    }
  },
  "sort": [
    {
      "age": {
        "order": "asc"
      }
    }
  ]
}

分頁查詢

#從第二條開始,取一條
GET lqz/_doc/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ]
}

GET lqz/_doc/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ], 
  "from": 2,
  "size": 2
}




###注意:對於`elasticsearch`來說,所有的條件都是可插拔的,彼此之間用`,`分割
GET lqz/_doc/_search
{
  "query": {
    "match_all": {}
  }, 
  "from": 2,
  "size": 2
}

布林查詢

- must(and)
- should(or)
- must_not(not)

##布林查詢之must and條件
GET lqz/_doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "from": "gu"
          }
        },
        {
          "match": {
            "name": "顧老二"
          }
        }
      ]
    }
  }
}


##布林查詢之should or條件
GET lqz/_doc/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "from": "gu"
          }
        },
        {
          "match": {
            "name": "龍套偏房"
          }
        }
      ]
    }
  }
}





### must_not條件   都不是
GET lqz/_doc/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "match": {
            "from": "gu"
          }
        },
        {
          "match": {
            "tags": "可愛"
          }
        },
        {
          "match": {
            "age": 18
          }
        }
      ]
    }
  }
}




###filter,大於小於的條件   gt lt  gte  lte
GET lqz/_doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "from": "gu"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "lt": 30
          }
        }
      }
    }
  }
}


### 範圍查詢
GET lqz/_doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "from": "gu"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "gte": 25,
            "lte": 30
          }
        }
      }
    }
  }
}


### filter需要在bool內部,並且如果是and條件,需要用must,如果使用了should,會認為是should和filter是或者的關係
  • must:與關係,相當於關係型資料庫中的and

  • should:或關係,相當於關係型資料庫中的or

  • must_not:非關係,相當於關係型資料庫中的not

  • filter:過濾條件。

  • range:條件篩選範圍。

  • gt:大於,相當於關係型資料庫中的>

  • gte:大於等於,相當於關係型資料庫中的>=

  • lt:小於,相當於關係型資料庫中的<

  • lte:小於等於,相當於關係型資料庫中的<=

    查詢結果過濾

    ###基本使用
    GET lqz/_doc/_search
    {
      "query": {
        "match_all": {
          }
      },
      "_source":["name","age"]
    }
    
    
    ####_source和query是平級的
    
    GET lqz/_doc/_search
    {
      "query": {
        "bool": {
          "must":{
            "match":{"from":"gu"}
          },
          
          "filter": {
            "range": {
              "age": {
                "lte": 25
              }
            }
          }
        }
      },
      "_source":["name","age"]
    }
    

    高亮查詢

    GET lqz/_doc/_search
    {
      "query": {
        "match": {
          "from": "gu"
        }
      },
      "highlight": {
        "pre_tags": "<b class='key' style='color:red'>",
        "post_tags": "</b>",
        "fields": {
          "from": {}
        }
      }
    }
    

    聚合查詢

    # sum ,avg, max ,min
    
    # select max(age) as my_avg from 表 where from=gu;
    GET lqz/_doc/_search
    {
      "query": {
        "match": {
          "from": "gu"
        }
      },
      "aggs": {
        "my_avg": {
          "avg": {
            "field": "age"
          }
        }
      },
      "_source": ["name", "age"]
    }
    
    #最大年齡
    GET lqz/_doc/_search
    {
      "query": {
        "match": {
          "from": "gu"
        }
      },
      "aggs": {
        "my_max": {
          "max": {
            "field": "age"
          }
        }
      },
      "_source": ["name", "age"]
    }
    
    #最小年齡
    GET lqz/_doc/_search
    {
      "query": {
        "match": {
          "from": "gu"
        }
      },
      "aggs": {
        "my_min": {
          "min": {
            "field": "age"
          }
        }
      },
      "_source": ["name", "age"]
    }
    
    # 總年齡
    #最小年齡
    GET lqz/_doc/_search
    {
      "query": {
        "match": {
          "from": "gu"
        }
      },
      "aggs": {
        "my_sum": {
          "sum": {
            "field": "age"
          }
        }
      },
      "_source": ["name", "age"]
    }
    
    
    
    #分組
    
    
    # 現在我想要查詢所有人的年齡段,並且按照`15~20,20~25,25~30`分組,並且算出每組的平均年齡。
    GET lqz/_doc/_search
    {
      "size": 0, 
      "query": {
        "match_all": {}
      },
      "aggs": {
        "age_group": {
          "range": {
            "field": "age",
            "ranges": [
              {
                "from": 15,
                "to": 20
              },
              {
                "from": 20,
                "to": 25
              },
              {
                "from": 25,
                "to": 30
              }
            ]
          }
        }
      }
    }
    

    ik分詞器使用

    #1 github下載相應版本
    https://github.com/medcl/elasticsearch-analysis-ik/releases?after=v7.5.2
    # 2 解壓到es的plugin目錄下
    # 3 重啟es
    
    
    
    # ik_max_word 和 ik_smart 什麼區別?
    
    ik_max_word: 會將文字做最細粒度的拆分,比如會將“中華人民共和國國歌”拆分為“中華人民共和國,中華人民,中華,華人,人民共和國,人民,人,民,共和國,共和,和,國國,國歌”,會窮盡各種可能的組合,適合 Term Query;
    
    ik_smart: 會做最粗粒度的拆分,比如會將“中華人民共和國國歌”拆分為“中華人民共和國,國歌”,適合 Phrase 查詢。
    
    
    PUT books
    {
      "mappings": {
        "properties":{
          "title":{
            "type":"text",
            "analyzer": "ik_max_word"
          },
          "price":{
            "type":"integer"
          },
          "addr":{
            "type":"keyword"
          },
          "company":{
            "properties":{
              "name":{"type":"text"},
              "company_addr":{"type":"text"},
              "employee_count":{"type":"integer"}
            }
          },
          "publish_date":{"type":"date","format":"yyy-MM-dd"}
          
        }
        
      }
    }
    
    PUT books/_doc/1
    {
      "title":"大頭兒子小偷爸爸",
      "price":100,  
      "addr":"北京天安門",
      "company":{
        "name":"我愛北京天安門",
        "company_addr":"我的家在東北松花江傻姑娘",
        "employee_count":10
      },
      "publish_date":"2019-08-19"
    }
    
    
    
    PUT books/_doc/2
    {
      "title":"白雪公主和十個小矮人",
      "price":"99",
      "addr":"黑暗森裡",
      "company":{
        "name":"我的家鄉在上海",
        "company_addr":"朋友一生一起走",
        "employee_count":10
      },
      "publish_date":"2018-05-19"
    }
    
    GET books/_mapping
    
    
    
    GET _analyze
    {
      "analyzer": "ik_max_word",
      "text": "白雪公主和十個小矮人"
    }
    GET books/_search
    {
      "query": {
        "match": {
          "title": "十"
        }
      }
    }
    
    
    
    PUT books2
    {
      "mappings": {
        "properties":{
          "title":{
            "type":"text",
            "analyzer": "ik_smart"
          },
          "price":{
            "type":"integer"
          },
          "addr":{
            "type":"keyword"
          },
          "company":{
            "properties":{
              "name":{"type":"text"},
              "company_addr":{"type":"text"},
              "employee_count":{"type":"integer"}
            }
          },
          "publish_date":{"type":"date","format":"yyy-MM-dd"}
          
        }
        
      }
    }
    
    
    PUT books2/_doc/1
    {
      "title":"大頭兒子小偷爸爸",
      "price":100,  
      "addr":"北京天安門",
      "company":{
        "name":"我愛北京天安門",
        "company_addr":"我的家在東北松花江傻姑娘",
        "employee_count":10
      },
      "publish_date":"2019-08-19"
    }
    
    
    
    PUT books2/_doc/2
    {
      "title":"白雪公主和十個小矮人",
      "price":"99",
      "addr":"黑暗森裡",
      "company":{
        "name":"我的家鄉在上海",
        "company_addr":"朋友一生一起走",
        "employee_count":10
      },
      "publish_date":"2018-05-19"
    }
    
    
    GET _analyze
    {
      "analyzer": "ik_smart",
      "text": "白雪公主和十個小矮人"
    }
    GET books2/_search
    {
      "query": {
        "match": {
          "title": "十個"
        }
      }
    }
    

    Python中整合ES兩種方式

    原生整合

    # Official low-level client for Elasticsearch
    
    ### 等同於pymysql
    #pip3 install elasticsearch
    
    
    from elasticsearch import Elasticsearch
    
    obj = Elasticsearch()   # 得到一個物件
    # 建立索引(Index)
    # result = obj.indices.create(index='user', body={"userid":'1','username':'lqz'},ignore=400)
    # print(result)
    # 刪除索引
    # result = obj.indices.delete(index='user', ignore=[400, 404])
    # 插入資料
    # data = {'userid': '1', 'username': 'lqz','password':'123'}
    # result = obj.create(index='news', doc_type='_doc', id=1, body=data)
    # print(result)
    # 更新資料
    '''
    不用doc包裹會報錯
    ActionRequestValidationException[Validation Failed: 1: script or doc is missing
    '''
    # data ={'doc':{'userid': '1', 'username': 'lqz','password':'123ee','test':'test'}}
    # result = obj.update(index='news', doc_type='_doc', body=data, id=1)
    # print(result)
    
    
    # 刪除資料
    # result = obj.delete(index='news', doc_type='_doc', id=1)
    # print(result)
    
    # 查詢
    # 查詢所有文件
    # query = {'query': {'match_all': {}}}
    #  查詢名字叫做jack的所有文件
    query = {'query': {'match': {'title': '十個'}}}
    
    # 查詢年齡大於11的所有文件
    # query = {'query': {'range': {'age': {'gt': 11}}}}
    
    allDoc = obj.search(index='books', doc_type='_doc', body=query)
    # print(allDoc)
    print(allDoc['hits']['hits'][0]['_source'])
    

    dsl整合

    
    
    
    # Elasticsearch DSL is a high-level
    
    # pip3 install elasticsearch-dsl
    
    
    
    from datetime import datetime
    from elasticsearch_dsl import Document, Date, Nested, Boolean,analyzer, InnerDoc, Completion, Keyword, Text,Integer
    
    from elasticsearch_dsl.connections import connections
    
    connections.create_connection(hosts=["localhost"])
    
    
    class Article(Document):
        title = Text(analyzer='ik_max_word')
        author = Text()
    
        class Index:
            name = 'myindex'
    
        def save(self, ** kwargs):
            return super(Article, self).save(** kwargs)
    
    
    if __name__ == '__main__':
        # Article.init()  # 建立索引
        # 儲存資料
        # article = Article()
        # article.title = "測試測試阿斯頓傳送到發斯蒂芬啊啊士大夫阿斯蒂芬"
        # article.author = "lqz"
        # article.save()  # 資料就儲存了
    
        #查詢資料
        # s=Article.search()
        # s = s.filter('match', title="測試")
        #
        # results = s.execute()  # 執行
        # print(results[0].title)
    
        #刪除資料
        s = Article.search()
        s = s.filter('match', title="李清照").delete()
    
        #修改資料
        # s = Article().search()
        # s = s.filter('match', title="測試")
        # results = s.execute()
        # print(results[0])
        # results[0].title="李清照阿斯頓傳送到傳送阿斯蒂"
        # results[0].save()
    

    叢集搭建(腦裂)

    # 1 廣播方式(一般不用)
    	-只要es節點能聯通,ping,自動加人到節點中
        
    # 2 單播方式
    
    
    
    #1 elasticsearch1節點,,叢集名稱是my_es1,叢集埠是9300;節點名稱是node1,監聽本地9200埠,可以有許可權成為主節點和讀寫磁碟(不寫就是預設的)。
    
    cluster.name: my_es1
    node.name: node1
    network.host: 127.0.0.1
    http.port: 9200
    transport.tcp.port: 9300
    discovery.zen.ping.unicast.hosts: ["127.0.0.1:9300", "127.0.0.1:9302", "127.0.0.1:9303", "127.0.0.1:9304"]
    
    # 2 elasticsearch2節點,叢集名稱是my_es1,叢集埠是9302;節點名稱是node2,監聽本地9202埠,可以有許可權成為主節點和讀寫磁碟。
    
    cluster.name: my_es1
    node.name: node2
    network.host: 127.0.0.1
    http.port: 9202
    transport.tcp.port: 9302
    node.master: true
    node.data: true
    discovery.zen.ping.unicast.hosts: ["127.0.0.1:9300", "127.0.0.1:9302", "127.0.0.1:9303", "127.0.0.1:9304"]
    
    # 3 elasticsearch3節點,叢集名稱是my_es1,叢集埠是9303;節點名稱是node3,監聽本地9203埠,可以有許可權成為主節點和讀寫磁碟。
    
    cluster.name: my_es1
    node.name: node3
    network.host: 127.0.0.1
    http.port: 9203
    transport.tcp.port: 9303
    discovery.zen.ping.unicast.hosts: ["127.0.0.1:9300", "127.0.0.1:9302", "127.0.0.1:9303", "127.0.0.1:9304"]
    
    # 4 elasticsearch4節點,叢集名稱是my_es1,叢集埠是9304;節點名稱是node4,監聽本地9204埠,僅能讀寫磁碟而不能被選舉為主節點。
    
    cluster.name: my_es1
    node.name: node4
    network.host: 127.0.0.1
    http.port: 9204
    transport.tcp.port: 9304
    node.master: false
    node.data: true
    discovery.zen.ping.unicast.hosts: ["127.0.0.1:9300", "127.0.0.1:9302", "127.0.0.1:9303", "127.0.0.1:9304"]
    
    由上例的配置可以看到,各節點有一個共同的名字my_es1,但由於是本地環境,所以各節點的名字不能一致,我們分別啟動它們,它們通過單播列表相互介紹,發現彼此,然後組成一個my_es1叢集。誰是老大則是要看誰先啟動了!
    
    
    
    #3 假設有7個節點
    	-由於網路問題  3個節點一組 , 4 個節點一組形成了兩個機器
        -防止腦列
        	防止腦裂,我們對最小叢集節點數該叢集設定引數:(叢集節點總數/2+1的個數)
    		discovery.zen.minimum_master_nodes: 3   # 3=5/2+1
    

    打分機制

    1 確定文件和查詢有多麼相關的過程被稱為打分
    2 TF是詞頻(term frequency):一個詞條在文件中出現的次數,出現的頻率越高,表示相關度越高 3 IDF`是逆文件頻率:如果一個詞條在索引中的不同文件中出現的次數越多,那麼它就越不重要