Elasticsearch學習方法以及複雜數據類型的映射

概述

Elasticsearch是一個基於Lucene的搜索服務器。以下簡稱ES,版本爲2.3左右的。

ES的版本比較多,目前已經到了5.3版本,但是很多公司都沒有使用最新版本,我所在的公司也是如此。在沒有接觸ES之前,我不知道這個全文索引的框架,加上我英文不好,學習的時候真的給我帶了不少的問題,踩了很多的坑。下面,我將從一個0基礎的角度來介紹我學習ES的過程。感謝我的指導老師騫哥、祥哥。

一、如何學習ES

ES的中文文檔並不多,在加上ES的版本很多,給翻譯帶來了很大的工作量。但是,我在學習過程中找到了一些文檔和資料,可以快速的讓你瞭解ES是什麼,該怎麼使用。

1.ES官方文檔

https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html

學習ES的官方文檔中的Getting Started,可以讓你對ES的概念有個大概的瞭解,包括ES的一些基本概念,ES的安裝,索引,查詢等方面的知識。但是對於英文不好的人來說,要理解這些概可能就需要看上個一兩天,都還不一定能懂。那麼請看條例2。

2.Getting Started的中文博客地址

http://blog.csdn.net/cnweike/article/details/33736429

這篇博客將Getting Started詳細的翻譯了一遍,結合上英文,再去理解,就比較容易了。

3.ES的中文翻譯社區地址(ES權威指南)

https://es.xiaoleilu.com/index.html

這ES權威指南書籍的電子文檔,這個網站已經翻譯了很多章節的內容,如果你對博客中給出的翻譯不滿意,可以結合本網站學習。這個網站有個毛病,不知道是電腦字庫渲染問題還是文檔本身的問題,翻譯中會有很多的字是錯的。另一個毛病便是切換文檔時需要等待很久,因此,需要你有足夠的耐心。ES權威指南有一個最大的優點,它選擇人們經常用的東西翻譯,這給開發帶來了極大的便利。

4.ES英文官網文檔學習路線

如果你急需在較短的時間內使用ES,那麼你可以按着下面的路線進行快速入門,並且學習一些高級的東西。下面的學習路線是擁有多年開發經驗同事給我規劃的,希望對你有用。我公司使用的ES版本是2.3,並且封裝了自己的框架。因此,你在查看文檔時,也需要查看相應的版本,版本不同,文檔的結構會有所變化。

① Getting Started 裏的所有內容;

② Setup Elasticsearch 裏的所有內容;

③ Document APIs 裏的所有內容;

④ Search APIs 下的 Search、URI Search、Request Body Search;

⑤ Query DSL 下的 Query and filter context、Match All Query、Full text queries下的Match Query, Compound queries下的 Bool Query, Joining queries下的 Nested Query。

⑥ Term level queries下的 Term Query、Terms Query、Rangge Query。這在查詢時會用到。

⑦ Mapping下Field datatypes下的Array datatype、Binary datatype、Range datatype、Boolean datatype、Date datatype、Object datatype、String datatype、Text datatype;這裏根據自己想買需求可多看一些其他的,這裏講解的是ES所支持的數據類型。

上面給出的,便是我接觸ES的學習路線,說實話,第一次接觸ES,我不僅看完了上面的全部,還看了很多。才把ES弄明白了一點點。

二、搭建ES時遇到的問題

ES的搭建在我看來,懂點Linux的人基本上不成問題,但是像我這種菜菜,就遇到了好多坑。不過我所遇到錯誤的原因都是權限問題。ES官網明確的說了一點,不要使用root用戶啓動,這是致命的

第二個問題是,ES的壓縮包解壓之後,就可以直接使用了,如果你對文件夾做權限的更改,那麼,啓動的時候就會報找不到Java環境等各種錯誤,起初我以爲是我沒有搭建Java環境,到頭來發現,並不是,遇到這個問題時,使用如下方式解決問題:

[yh@centos bin]$ sudo chown -R elasticsearc安裝文件夾  yh.yh

例如: sudo chown -R elasticsearch yaohong.yaohong(這個是用戶)

執行以上命令之後,那麼Elasticsearch就可以正常啓動了,如果遇到別的問題,那麼不好意思,百度吧!

啓動ES的方法

解壓文件之後,進入bin目錄,然後執行以下命令,ES便啓動了。

[yh@centos bin]$ ./elasticsearch

如果想在後臺啓動,使用-d參數,命令如下:

[yh@centos bin]$ ./elasticsearch -d

如果不是後臺啓動,你將看到如下信息,如果沒有如下信息,說明ES啓動失敗了!

[2017-04-24 10:36:53,706][INFO ][node                     ] [Mist Mistress] version[2.4.4], pid[12159], build[fcbb46d/2017-01-03T11:33:16Z]
[2017-04-24 10:36:53,707][INFO ][node                     ] [Mist Mistress] initializing ...
[2017-04-24 10:36:55,021][INFO ][plugins                  ] [Mist Mistress] modules [lang-groovy, reindex, lang-expression], plugins [], sites []
[2017-04-24 10:36:55,069][INFO ][env                      ] [Mist Mistress] using [1] data paths, mounts [[/ (rootfs)]], net usable_space [11.9gb], net total_space [19.5gb], spins? [unknown], types [rootfs]
[2017-04-24 10:36:55,069][INFO ][env                      ] [Mist Mistress] heap size [1015.6mb], compressed ordinary object pointers [true]
[2017-04-24 10:36:59,763][INFO ][node                     ] [Mist Mistress] initialized
[2017-04-24 10:36:59,770][INFO ][node                     ] [Mist Mistress] starting ...
[2017-04-24 10:37:00,014][INFO ][transport                ] [Mist Mistress] publish_address {127.0.0.1:9301}, bound_addresses {127.0.0.1:9301}
[2017-04-24 10:37:00,031][INFO ][discovery                ] [Mist Mistress] elasticsearch/a-VF8e_uQZ2y0k-wB_eeug
[2017-04-24 10:37:03,389][INFO ][cluster.service          ] [Mist Mistress] detected_master {Anelle}{K2u_6PgETsG5BifXQxfO2w}{127.0.0.1}{127.0.0.1:9300}, added {{Anelle}{K2u_6PgETsG5BifXQxfO2w}{127.0.0.1}{127.0.0.1:9300},}, reason: zen-disco-receive(from master [{Anelle}{K2u_6PgETsG5BifXQxfO2w}{127.0.0.1}{127.0.0.1:9300}])
[2017-04-24 10:37:03,855][INFO ][http                     ] [Mist Mistress] publish_address {127.0.0.1:9201}, bound_addresses {127.0.0.1:9201}
[2017-04-24 10:37:03,860][INFO ][node                     ] [Mist Mistress] started

如果你是後臺啓動,將看不到任何輸出,除非出錯了,可以使用如下命令,查看都端口情況:

[yh@centos bin]$ netstat -apn | grep 9200

三、一些ES的概念

1.ES中的Bool查詢有三種狀態,分別是must,should,must_not。說實話,我都懷疑我的語文是體育老師教的,當時我看到這個時,想了很久都沒有搞懂。在加上看的是英文,我更懵逼了。如果你有SQL語言的基礎,那麼就很好理解了。

① must 相當於 SQL 的 and條件,比如你用SQL查詢價格,你會寫出如下sql語句:

select * from table_name where id = 1000 and price = 50;

這樣的語句就相當於ES的must查詢。

② shoud相當於SQL 的 or條件,例如:

select * from table_name where id = 1000 or price = 50;

③ must_not 相當於SQL的not in,例如:

select * from table_name where id not in(1000);

must_not即不包含某某。

對於大於等於,區間值等,API的文檔中有詳細的說明。

如果你想知道更多的概念,那麼請點擊我上面說明的連接地址,他們講解的更清楚,我不在造輪子。

四、應用思路

1.學習ES的相關基礎知識和概念;
2.瞭解項目需求;
3.考慮ES的所需功能是否能夠解決當前的項目需求;
4.考慮之後,部署ES,如果能力可能,可自行封裝一層,原生的ES操作比較複雜,數據拼接容易出錯且不好維護;
5.編寫Mapping,建立索引;
6.導入數據;
7.數據導入之後便可查詢、重索引等各種測試,如果沒有數據,一切都是瞎忙活;
8.應用到實際項目中。

由於小編也是剛接觸ES不久,因此上面說的步驟不一定適合你,上面步驟是我經驗豐厚的同事教的方法,我根據他教的方法終結出來的。這裏我只是提供我自己學習的路線,你可以自己根據自己的能力調整。

五、Mapping映射(高級)

雖然ES可以根據數據的格式自動創建Mapping,他將所有的對象都映射成Object,但很多時候是不滿足項目需求的,基礎的Mapping映射我就不解釋,官方文檔比我說得清楚,不需要你看英文說明,僅看代碼就秒懂,並且網上一搜一大堆。我在做項目時遇到的映射,在網上並沒有找到。首先,請看下面這個json數據,我們需求是,能夠查詢字段”schedule_info”中時間區間或者日期區間,看到這個json你也許知道,sql是做不到的(”schedule_info字段是以json字符串保存到數據庫中的”),而ES是可以的,但是ES要實現這個功能,需要用到Nested查詢,那麼在寫Mapping時,就必須將其轉化爲對象。

{
    "id": 1000017,
    "status": 0,
    "name": "HHH",
    "daily_budget": 410000,
    "schedule_info": {
        "date": [
            {
                "start": "2017-04-20",
                "end": "2017-04-20"
            },
             {
                "start": "2017-04-20",
                "end": "2017-04-20"
            }
        ],
        "time": [
            {
                "start": "00:00",
                "end": "23:59"
            },
             {
                "start": "00:00",
                "end": "23:59"
            }
        ]
    },
    "serving_speed": 0,
    "create_time": 1492694481227,
    "start_schedule": 1492694481227,
    "end_schedule": 1499994481227,
    "create_user": "admin",
    "update_user": "unknown"

}

“schedule_info”字段包含了一個date和time兩個屬性,而這兩個屬性是都是數據,那麼在寫mapping時,該怎麼寫,我在做項目時,琢磨了一天,才弄明白ES的對象嵌套映射。下面是我的mapping。

{
  "order": 0,
  "template": "Yaohong-plan-*",
  "settings": {
    "index": {
      "number_of_replicas": "1",
      "number_of_shards": "5",
      "refresh_interval": "1s"
    }
  },
  "mappings": {
    "_default_": {
      "properties": {
        "update_user": {
          "index": "not_analyzed",
          "type": "string"
        },
        "status": {
          "type": "integer"
        },
        "end_schedule": {
          "format": "yyyy-MM-dd HH:mm:ss||epoch_millis",
          "type": "date"
        },
        "serving_speed": {
          "type": "integer"
        },
        "id": {
          "type": "long"
        },
        "update_time": {
          "format": "yyyy-MM-dd HH:mm:ss||epoch_millis",
          "type": "date"
        },
        "start_schedule": {
          "format": "yyyy-MM-dd HH:mm:ss||epoch_millis",
          "type": "date"
        },
        "daily_budget": {
          "type": "integer"
        },
        "create_time": {
          "format": "yyyy-MM-dd HH:mm:ss||epoch_millis",
          "type": "date"
        },
        "create_user": {
          "index": "not_analyzed",
          "type": "string"
        },
        "schedule_info": {
          "type":"nested",
          "properties":{
            "date":{
              "properties":{
                "start":{
                  "type":"date",
                  "format":"yyyy-MM-dd||epoch_millis"
                },
                "end":{
                  "type":"date",
                  "format":"yyyy-MM-dd||epoch_millis"
                }
              }
            },
            "time":{
              "properties":{
                "start":{
                  "type":"integer"
                },
                "end":{
                  "type":"integer"
                }
              }
            }
          }
        }
      },
      "_all": {
        "enabled": false
      }
    }
  },
  "aliases": {
    "Yaohong-plan-active": {}
  }
}

那麼如果我需要查詢日期在某個區間怎麼去查詢呢?請看下面的查詢語句:

{
  "bool" : {
    "must" : [ {
      "term" : {
        "status" : "0"
      }
    }, {
      "nested" : {
        "query" : {
          "bool" : {
            "filter" : [ {
              "range" : {
                "schedule_info.date.start" : {
                  "from" : "2017-03-05",
                  "to" : null,
                  "format" : "yyyy-MM-dd",
                  "include_lower" : true,
                  "include_upper" : true
                }
              }
            }, {
              "range" : {
                "schedule_info.date.end" : {
                  "from" : null,
                  "to" : "2017-09-12",
                  "format" : "yyyy-MM-dd",
                  "include_lower" : true,
                  "include_upper" : true
                }
              }
            } ]
          }
        },
        "path" : "schedule_info"
      }
    } ],
    "should" : {
      "match" : {
        "name" : {
          "query" : "YangHong",
          "type" : "boolean"
        }
      }
    }
  }
}

從查詢語句可以看出,ES對對象進行了扁平化的處理方式,如schedule_info.date.endDate,基於別的對象或者是數組的映射,官方文檔都有很詳細的說明,我給出的例子,在官方文檔是沒有的,因此分享給大家,當你看完這個例子,相信別的複雜映射都可以解決了。

另外需要說明的是,ES查詢日期類型時,其查詢格式必須與Mapping映射時的格式一模一樣,否則會出錯,對於單純的時間查詢,需要轉化成可比較的數據類型,像“06.30”這樣的時間數據,ES會以字符串的形式比較,從而得不到正確的結果。在此例子中,我將時間轉化成爲了整型,方便查找時間區間。

由於小編能力有限,如有錯誤,請指正,謝謝合作!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章