Elasticsearch入門教程

1.  什麼是 Elasticsearchcss

Elastic是一個實時的分佈式搜索分析引擎, 它能讓你以一個以前從未有過的速度和規模,去探索你的數據。 它被用做全文檢索、結構化搜索、分析以及這三個功能的組合。html

2.  安裝

  • Elasticsearch 須要 Java 8 環境

2.1. Windows上運行ElasticSearch

下載安裝包 elasticsearch-6.2.4.zip https://www.elastic.co/downloads/elasticsearchjava

解壓壓縮包,其目錄結構以下:node

從命令窗口運行位於bin文件夾中的elasticsearch.bat,可使用CTRL + C中止或關閉它mysql


見到xxxx started,那麼就是啓動完成了,打開瀏覽器輸入http:\\localhost:9200http:\\127.0.0.1:9200,若是出現如下文本證實啓動成功了。git

{
  "name" : "ubH8NDf",  
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "sJfrIwlVRBmAArbWRLWyEA",  
  "version" : {
    "number" : "6.2.4",
    "build_hash" : "ccec39f",
    "build_date" : "2018-04-12T20:37:28.497551Z",
    "build_snapshot" : false,
    "lucene_version" : "7.2.1",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}

 

默認狀況下,Elastic 只容許本機訪問,若是須要遠程訪問,能夠修改 Elastic 安裝目錄的config/elasticsearch.yml文件,去掉network.host的註釋,將它的值改爲0.0.0.0,而後從新啓動 Elastic。github

network.host: 0.0.0.0sql

上面代碼中,設成0.0.0.0讓任何人均可以訪問。線上服務不要這樣設置,要設成具體的 IP。數據庫

2.2.  集羣搭建

  1. 準備好三個文件夾
  2. 修改配置文件:進入到其中某個節點文件中config文件夾中,打開elasticsearch.yml進行配置
  3. 具體的配置信息參考以下:
    節點1的配置信息:  
    http.cors.enabled: true #是否容許跨域
    http.cors.allow-origin: "*"
    cluster.name: my-esLearn   #集羣名稱,保證惟一  
    node.name: node-1   #節點名稱,必須不同  
    network.host: 10.118.16.83   #必須爲本機的ip地址  
    http.port: 9200   #服務端口號,在同一機器下必須不同  
    transport.tcpport: 9300   #集羣間通訊端口號,在同一機器下必須不同  
    #設置集羣自動發現機器ip集合  
    discovery.zen.ping.unicast.hosts: ["10.118.16.83:9300", "10.118.16.83:9301", "10.118.16.83:9302"]  
    
    節點2的配置信息:  
    http.cors.enabled: true  #是否容許跨域
    http.cors.allow-origin: "*"
    cluster.name: my-esLearn   #集羣名稱,保證惟一  
    node.name: node-2   #節點名稱,必須不同  
    network.host: 10.118.16.83   #必須爲本機的ip地址  
    http.port: 9201   #服務端口號,在同一機器下必須不同  
    transport.tcpport: 9301   #集羣間通訊端口號,在同一機器下必須不同  
    #設置集羣自動發現機器ip集合  
    discovery.zen.ping.unicast.hosts: ["10.118.16.83:9300", "10.118.16.83:9301", "10.118.16.83:9302"]  
    
    節點3的配置信息:  
    http.cors.enabled: true #是否容許跨域
    http.cors.allow-origin: "*"
    cluster.name: my-esLearn   #集羣名稱,保證惟一  
    node.name: node-3   #節點名稱,必須不同  
    network.host: 10.118.16.83   #必須爲本機的ip地址  
    http.port: 9202   #服務端口號,在同一機器下必須不同  
    transport.tcpport: 9302   #集羣間通訊端口號,在同一機器下必須不同  
    #設置集羣自動發現機器ip集合  
    discovery.zen.ping.unicast.hosts: ["10.118.16.83:9300", "10.118.16.83:9301", "10.118.16.83:9302"] `
    View Code

2.3.  elasticsearch-head的搭建

解壓已經下載 elasticsearch-head-master.zip,同時確認本機已經安裝好nodejs,cmd->node -v確認nodejs是否安全成功。apache

解壓壓縮包,切換到elasticsearch-head-master已解壓好的文件夾下。

c:\elasticsearch-head-master>npm install
c:\elasticsearch-head-master>npm start

用瀏覽器打開,http://10.118.16.83:9100/, 只要出現下圖界面就證實成功了。

3.  基本概念

  • 集羣(Cluster)

ES集羣是一個或多個節點的集合,它們共同存儲了整個數據集,並提供了聯合索引以及可跨全部節點的搜索能力。多節點組成的集羣擁有冗餘能力,它能夠在一個或幾個節點出現故障時保證服務的總體可用性。集羣靠其獨有的名稱進行標識,默認名稱爲「elasticsearch」。節點靠其集羣名稱來決定加入哪一個ES集羣,一個節點只能屬一個集羣。

  • 節點(node)

一個節點是一個邏輯上獨立的服務,能夠存儲數據,並參與集羣的索引和搜索功能, 一個節點也有惟一的名字,羣集經過節點名稱進行管理和通訊.

  •  主節點

主節點的主要職責是和集羣操做相關的內容,如建立或刪除索引,跟蹤哪些節點是羣集的一部分,並決定哪些分片分配給相關的節點。穩定的主節點對集羣的健康是很是重要的。雖然主節點也能夠協調節點,路由搜索和從客戶端新增數據到數據節點,但最好不要使用這些專用的主節點。一個重要的原則是,儘量作儘可能少的工做。

對於大型的生產集羣來講,推薦使用一個專門的主節點來控制集羣,該節點將不處理任何用戶請求。

  • 數據節點

持有數據和倒排索引。

  •  客戶端節點

它既不能保持數據也不能成爲主節點,該節點能夠響應用戶的狀況,把相關操做發送到其餘節點;客戶端節點會將客戶端請求路由到集羣中合適的分片上。對於讀請求來講,協調節點每次會選擇不一樣的分片處理請求,以實現負載均衡。

  • 索引Index

ES將數據存儲於一個或多個索引中,索引是具備相似特性的文檔的集合。類比傳統的關係型數據庫領域來講,索引至關於SQL中的一個數據庫,或者一個數據存儲方案(schema)。索引由其名稱(必須爲全小寫字符)進行標識,並經過引用此名稱完成文檔的建立、搜索、更新及刪除操做。一個ES集羣中能夠按需建立任意數目的索引。每一個 Index (即數據庫)的名字必須是小寫。
下面的命令能夠查看當前節點的全部 Index

$ curl -X GET 'http://10.118.16.83:9200/_cat/indices?v'
  • 文檔類型(Type)

索引內部的邏輯分區(category/partition),然而其意義徹底取決於用戶需求。所以,一個索引內部可定義一個或多個類型(type)。通常來講,類型就是爲那些擁有相同的域的文檔作的預約義。例如,在索引中,能夠定義一個用於存儲用戶數據的類型,一個存儲日誌數據的類型,以及一個存儲評論數據的類型。類比傳統的關係型數據庫領域來講,類型至關於「表」

  •  文檔Document

Lucene索引和搜索的原子單位,它是包含了一個或多個域的容器,基於JSON格式進行表示。文檔由一個或多個域組成,每一個域擁有一個名字及一個或多個值,有多個值的域一般稱爲「多值域」。每一個文檔能夠存儲不一樣的域集,但同一類型下的文檔至應該有某種程度上的類似之處。至關於數據庫的「記錄」,例如:

{
  "user": "張三",
  "title": "工程師",
  "desc": "數據庫管理"
}
View Code

同一個 Index 裏面的 Document,不要求有相同的結構(scheme),可是最好保持相同,這樣有利於提升搜索效率。

  •  Mapping

至關於數據庫中的schema,用來約束字段的類型,不過 Elastic的 mapping 能夠自動根據數據建立

ES中,全部的文檔在存儲以前都要首先進行分析。用戶可根據須要定義如何將文本分割成token、哪些token應該被過濾掉,以及哪些文本須要進行額外處理等等。

分片(shard) :ES的「分片(shard)」機制可將一個索引內部的數據分佈地存儲於多個節點,它經過將一個索引切分爲多個底層物理的Lucene索引完成索引數據的分割存儲功能,這每個物理的Lucene索引稱爲一個分片(shard)。

每一個分片其內部都是一個全功能且獨立的索引,所以可由集羣中的任何主機存儲。建立索引時,用戶可指定其分片的數量,默認數量爲5個

4.  數據操做

4.1.  文檔更新

  4.1.1. 新增

向指定的 /Index/Type 發送 PUT 請求,就能夠在 Index 裏面新增一條記錄。

$ curl -H "Content-Type:application/json" -X PUT '10.118.16.83:9200/megacorp/employee/1' -d '
{
    "first_name" : "John",
    "last_name" :  "Smith",
    "age" :        25,
    "about" :      "I love to go rock climbing",
    "interests": [ "sports", "music" ]
}'
View Code

返回:

{
    "_index": "megacorp",
    "_type": "employee",
    "_id": "1",
    "_version": 1,
    "result": "created",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 0,
    "_primary_term": 1
}
View Code

若不指定id, 則改成Post請求 。id字段就是一個隨機字符串。

再新增兩條:

$ curl -H "Content-Type:application/json" -X PUT '10.118.16.83:9200/megacorp/employee/2' -d '
{
    "first_name" :  "Jane",
    "last_name" :   "Smith",
    "age" :         32,
    "about" :       "I like to collect rock albums",
    "interests":  [ "music" ]
}'
 
$ curl -H "Content-Type:application/json" -X PUT '10.118.16.83:9200/megacorp/employee/3' -d '
{
    "first_name" :  "Douglas",
    "last_name" :   "Fir",
    "age" :         35,
    "about":        "I like to build cabinets",
    "interests":  [ "forestry" ]
}'
View Code

 4.1.2. 更新

更新記錄就是使用 PUT 請求,從新發送一次數據。

$ curl -H "Content-Type:application/json" -X PUT '10.118.16.83:9200/megacorp/employee/1' -d '
{
    "first_name" : "John",
    "last_name" :  "Smith",
    "age" :        26,
    "about" :      "I love to go rock climbing",
    "interests": [ "sports", "music" ]
}' 
View Code
返回:
{
    "_index": "megacorp",
    "_type": "employee",
    "_id": "3",
    "_version": 2,
    "result": "updated",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 1,
    "_primary_term": 1
}
View Code

記錄的 Id 沒變,可是版本(version)從1變成2,操做類型(result)從created變成updated,created字段變成false,由於此次不是新建記錄

4.1.3. 檢索文檔

$ curl '10.118.16.83:9200/megacorp/employee/1'

 刪除

刪除記錄就是發出 DELETE 請求

$ curl -X DELETE '10.118.16.83:9200/megacorp/employee/1'

4.2.    返回全部記錄

使用 GET 方法,直接請求/Index/Type/_search,就會返回全部記錄。

$ curl '10.118.16.83:9200/accounts/person/_search'
 
{
    "took": 4,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 3,
        "max_score": 1,
        "hits": [
            {
                "_index": "megacorp",
                "_type": "employee",
                "_id": "2",
                "_score": 1,
                "_source": {
                    "first_name": "John",
                    "last_name": "Smith",
                    "age": 25,
                    "about": "I love to go rock climbing",
                    "interests": [
                        "sports",
                        "music"
                    ]
                }
            },
            …//此處省略
        ]
    }
}
View Code

上面代碼中,返回結果的 took字段表示該操做的耗時(單位爲毫秒),timed_out字段表示是否超時,hits字段表示命中的記錄,裏面子字段的含義以下。
total:返回記錄數,本例是3條。
max_score:最高的匹配程度,本例是1.0。
hits:返回的記錄組成的數組。
返回的記錄中,每條記錄都有一個_score字段,表示匹配的程序,默認是按照這個字段降序排列。

4.3.    匹配查詢

Elastic提供兩種方式:

l  Query-string 搜索經過命令很是方便地進行臨時性的即席搜索 ,但它有自身的侷限性。

$ curl '10.118.16.83:9200/megacorp/employee/_search?q=last_name:Smith'

l  提供一個豐富靈活的查詢語言叫作 查詢表達式 , 它支持構建更加複雜和健壯的查詢。領域特定語言 (DSL), 指定了使用一個 JSON 請求

$ curl -H "Content-Type:application/json" '10.118.16.83:9200/megacorp/employee/_search'  -d '
{
  "query" : { "match" : { "last_name" : " Smith" }}
}'

4.4.    過濾查詢

一樣搜索姓氏爲 Smith 的僱員,但此次咱們只須要年齡大於 30 的。查詢須要稍做調整,使用過濾器 filter [range ],它支持高效地執行一個結構化查詢。

$ curl -H "Content-Type:application/json" '10.118.16.83:9200/megacorp/employee/_search'  -d '
{
  "query" : {
        "bool": {
            "must": {
                "match" : {
                    "last_name" : "smith" 
                }
            },
            "filter": {
                "range" : {
                    "age" : { "gt" : 30 } 
                }
            }
        }
    }
}' 
View Code

4.5.    全文搜索

截止目前的搜索相對都很簡單:單個姓名,經過年齡過濾。如今嘗試下稍微高級點兒的全文搜索——一項 傳統數據庫確實很難搞定的任務。搜索下全部喜歡攀巖(rock climbing)的僱員。

$ curl -H "Content-Type:application/json" '10.118.16.83:9200/megacorp/employee/_search'  -d '
{
    "query" : {
        "match" : {
            "about" : "rock climbing"
        }
    }
}'
View Code

獲得兩個匹配的文檔

這是一個很好的案例,闡明瞭 Elasticsearch 如何 在 全文屬性上搜索並返回相關性最強的結果。Elasticsearch中的 相關性 概念很是重要,也是徹底區別於傳統關係型數據庫的一個概念,數據庫中的一條記錄要麼匹配要麼不匹配。

4.6.    短語搜索

找出一個屬性中的獨立單詞是沒有問題的,但有時候想要精確匹配一系列單詞或者短語 。 好比, 咱們想執行這樣一個查詢,僅匹配同時包含 「rock」 和 「climbing」 ,而且 兩者以短語 「rock climbing」 的形式緊挨着的僱員記錄。

爲此對 match 查詢稍做調整,使用一個叫作 match_phrase 的查詢:

$ curl -H "Content-Type:application/json" '10.118.16.83:9200/megacorp/employee/_search'  -d '
{
  "query" : {
        "match_phrase" : {
            "about" : "rock climbing"
        }
    }
}'
View Code

4.7.    高亮搜索

許多應用都傾向於在每一個搜索結果中 高亮 部分文本片斷,以便讓用戶知道爲什麼該文檔符合查詢條件。在 Elasticsearch 中檢索出高亮片斷也很容易。

再次執行前面的查詢,並增長一個新的 highlight 參數:

$ curl -H "Content-Type:application/json" '10.118.16.83:9200/megacorp/employee/_search'  -d '
{
  "query" : {
        "match_phrase" : {
            "about" : "rock climbing"
        }
    },
    "highlight": {
        "fields" : {
            "about" : {}
        }
    }
}'
View Code

查詢結果:

4.8.    聚合

Elasticsearch 有一個功能叫聚合(aggregations),容許咱們基於數據生成一些精細的分析結果。聚合與 SQL 中的 GROUP BY 相似但更強大。

舉個例子,挖掘出僱員中最受歡迎的興趣愛好:

$ curl -H "Content-Type:application/json" '10.118.16.83:9200/megacorp/employee/_search'  -d '
{
  "aggs": {
    "all_interests": {
      "terms": { "field": "interests" },
          "aggs": { //爲指標新增aggs層

              "avg_age": { //指定指標的名字,在返回的結果中也是用這個變量名來儲存數值的

                 "avg": {//指標參數:平均值

                       "field": "age" //明確求平均值的字段爲'age'

                  }

              }

          }
}
  }
}'
View Code

執行失敗:

{
  "error": {
    "root_cause": [
      {
        "type": "illegal_argument_exception",
        "reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [interests] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory."
      }
    ],
    "type": "search_phase_execution_exception",
    "reason": "all shards failed",
    "phase": "query",
    "grouped": true,
    "failed_shards": [
      {
        "shard": 0,
        "index": "megacorp",
        "node": "-Md3f007Q3G6HtdnkXoRiA",
        "reason": {
          "type": "illegal_argument_exception",
          "reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [interests] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory."
        }
      }
    ],
    "caused_by": {
      "type": "illegal_argument_exception",
      "reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [interests] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory."
    }
  },
  "status": 400
}
View Code

排序,聚合這些操做用單獨的數據結構(fielddata)緩存到內存裏了,須要單獨開啓,官方解釋在此fielddata

$ curl -H "Content-Type:application/json" -X POST '10.118.16.83:9200/megacorp/_mapping/employee' -d '

{

    "properties":{

        "interests":{

            "type":"text",

            "fielddata":true

        }

    }

}'
View Code

 

切記,這裏一旦類型錯誤,之後可就麻煩咯

查詢結果:

{"took":40,"timed_out":false,"_shards":{"total":5,"successful":5,"skipped":0,"failed":0},"hits":{"total":4,"max_score":1.0,"hits":[{"_index":"megacorp","_type":"employee","_id":"_cat","_score":1.0,"_source":{

    "properties":{

        "age":{

            "type":"integer",

            "fielddata":true

        }

    }

}

},{"_index":"megacorp","_type":"employee","_id":"2","_score":1.0,"_source":{

    "first_name" :  "Jane",

    "last_name" :   "Smith",

    "age" :         32,

    "about" :       "I like to collect rock albums",

    "interests":  [ "music" ]

 

}

},{"_index":"megacorp","_type":"employee","_id":"1","_score":1.0,"_source":{

    "first_name" : "John",

    "last_name" :  "Smith",

    "age" :        25,

    "about" :      "I love to go rock climbing",

    "interests": [ "sports", "music" ]

}

},{"_index":"megacorp","_type":"employee","_id":"3","_score":1.0,"_source":{

 "first_name" :  "Douglas",

    "last_name" :   "Fir",

    "age" :         35,

    "about":        "I like to build cabinets",

    "interests":  [ "forestry" ]
}

}]},"aggregations":{"all_interests":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"music","doc_count":2,"avg_age":{"value":28.5}},{"key":"forestry","doc_count":1,"avg_age":{"value":35.0}},{"key":"sports","doc_count":1,"avg_age":{"value":25.0}}]}}}
View Code

Java實現

@Test

    public void aggsTermsQuery() {

        SearchResponse response = client.prepareSearch("cars")

                .setTypes("transactions")

                .addAggregation(AggregationBuilders.terms("all_interests").field("interests")

                        .subAggregation(AggregationBuilders.avg("avg_price")

                                .field("price")))

                .setSize(0)

                .get();
        Map<String, Aggregation> aggMap = response.getAggregations().asMap();

        StringTerms teamAgg= (StringTerms) aggMap.get("popular_colors"); 

        Iterator<Bucket> teamBucketIt = teamAgg.getBuckets().iterator(); 

        while (teamBucketIt .hasNext()) { 

            Bucket buck = teamBucketIt .next(); 

            //max/min以此類推 

            logger.info(buck.getKeyAsString() + ", " + buck.getDocCount());

            Map<String, Aggregation> subAggMap = buck.getAggregations().asMap();

            long avgAgg= (long) ((InternalAvg)subAggMap.get("avg_price")).getValue();

            logger.info("avg:{}", avgAgg);
        } 

    }
View Code

4.9.  排序與分頁

Elastic使用sort進行排序,默認一次返回10條結果,能夠經過size字段改變這個設置。還能夠經過from字段,指定位移。

GET /_search
{
    "query" : {
        "bool" : {
            "filter" : { "term" : { "user_id" : 1 }}
        }
    },
    "sort": { "date": { "order": "desc" }},
"from": 1,
    "size": 1
 
}
View Code

5.  中文分詞設置

5.1. 安裝分詞插件

注意:安裝對應版本的插件。
下載插件https://github.com/medcl/elasticsearch-analysis-ik/releases

5.2. 使用 IK Analysis

要使用 IK Analysis,須要在文檔類裏面,指定相應的分詞器。

ik_max_word 和 ik_smart 區別
ik_max_word: 會將文本作最細粒度的拆分,好比會將「中華人民共和國國歌」拆分爲「中華人民共和國,中華人民,中華,華人,人民共和國,人民,人,民,共和國,共和,和,國國,國歌」,會窮盡各類可能的組合;

ik_smart: 會作最粗粒度的拆分,好比會將「中華人民共和國國歌」拆分爲「中華人民共和國,國歌」。

具體使用可參考https://github.com/medcl/elasticsearch-analysis-ik

public void highlighter() throws UnknownHostException {
    String preTags = "<strong>";  
    String postTags = "</strong>"; 
    HighlightBuilder highlightBuilder = new HighlightBuilder(); 
    highlightBuilder.preTags(preTags);//設置前綴  
    highlightBuilder.postTags(postTags);//設置後綴  
    highlightBuilder.field("content");

    SearchResponse response = client.prepareSearch("msg")
            .setTypes("tweet")
            .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
            .setQuery(QueryBuilders.matchQuery("content", "中國"))
            .highlighter(highlightBuilder)
            .setFrom(0).setSize(60).setExplain(true)
            .get();

    logger.info("search response is:total=[{}]",response.getHits().getTotalHits());
    SearchHits hits = response.getHits();
    for (SearchHit hit : hits) {
        logger.info("{} -- {} -- {}", hit.getId(), hit.getSourceAsString(), hit.getHighlightFields());
    }

    SearchRequestBuilder builder = client.prepareSearch("msg")
            .setTypes("tweet")
            .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
            .setQuery(QueryBuilders.matchQuery("content", "中國"));

} 
View Code

6.  經過Java程序鏈接Elasticsearch

 須要注意的是,咱們經過瀏覽器 http://10.118.16.83:9200 訪問能夠正常訪問,這裏須要知曉,9200端口是用於Http協議訪問的,若是經過客戶端訪問須要經過9300端口才能夠訪問

pom.xml添加依賴

<!-- Elasticsearch核心依賴包 -->
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>transport</artifactId>
        <version>6.2.4</version>
    </dependency>
    <!-- 日誌依賴 -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.21</version>
        <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.8.2</version>
    </dependency>
View Code

6.1. 單點

import java.net.InetAddress;
import java.net.UnknownHostException;

import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.junit.Test;

public class ElasticsearchTest1 {
    public static final String HOST = "127.0.0.1";

    public static final int PORT = 9200; //http請求的端口是9200,客戶端是9300

    @SuppressWarnings("resource")
    @Test
    public void test1() throws UnknownHostException {
        TransportClient client = new PreBuiltTransportClient(Settings.EMPTY).addTransportAddress(
                new TransportAddress(InetAddress.getByName(HOST), PORT));
        System.out.println("Elasticssearch connect info:" + client.toString());
        client.close();
    }
} 
View Code

6.2. 集羣

import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;

import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ElasticsearchTest2 {
    public static final String HOST = "10.118.16.83";

    public static final int PORT = 9300; //http請求的端口是9200,客戶端是9300

    private TransportClient client = null;

    private Logger logger = LoggerFactory.getLogger(ElasticsearchTest2.class);

    public static final String CLUSTER_NAME = "my-esLearn"; //實例名稱

    //1.設置集羣名稱:默認是elasticsearch,並設置client.transport.sniff爲true,使客戶端嗅探整個集羣狀態,把集羣中的其餘機器IP加入到客戶端中  
    private static Settings settings = Settings.builder()
            .put("cluster.name",CLUSTER_NAME)  
            .put("client.transport.sniff", true)  
            .build();  

    /**
     * 獲取客戶端鏈接信息
     * @Title: getConnect
     * @author ld
     * @date 2018-05-03
     * @return void
     * @throws UnknownHostException
     */
    @SuppressWarnings("resource")
    @Before
    public void getConnect() throws UnknownHostException {
        client = new PreBuiltTransportClient(settings).addTransportAddress(
                new TransportAddress(InetAddress.getByName(HOST), PORT));
        logger.info("鏈接信息:" + client.toString());
    }

    @After
    public void closeConnect() {
        if (client != null) {
            client.close();
        }
    }

    @Test
    public void test1() throws UnknownHostException {
        logger.info("Elasticssearch connect info:" + client.toString());
    }

    @Test
    public void addIndex() throws IOException {
        IndexResponse response = client.prepareIndex("msg", "tweet", "2").setSource(
                XContentFactory.jsonBuilder()
                .startObject()
                .field("userName", "es")
                .field("msg", "Hello,Elasticsearch")
                .field("age", 14)
                .endObject()).get();
    }

    @Test
    public void search() {
        SearchResponse response = client.prepareSearch("msg")
                .setTypes("tweet")
                .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                .setQuery(QueryBuilders.matchPhraseQuery("user_name", "es"))
                .setFrom(0).setSize(60).setExplain(true)
                .get();

        logger.info("search response is:total=[{}]",response.getHits().getTotalHits());
        SearchHits hits = response.getHits();
        for (SearchHit hit : hits) {
            logger.info(hit.getId());
            logger.info(hit.getSourceAsString());
        }
    }
}
View Code

7.  mysql與elasticsearch同步

可參考elasticsearch與數據庫同步工具Logstash-input-jdbc

8.  與solr的比較

 

solr

Elastic

功能

官方提供的功能更多

官方功能少,可是第三方插件很豐富,擴展能力更強

創建索引和查詢效率

創建索引的速度和Es差很少,索引創建完成後的檢索速度也很快,可是一邊創建索引一邊搜索會很慢(創建索引時會形成IO阻塞)

 創建索引速度和solr差很少,第一次檢索會比solr慢,以後就快了。一邊創建索引一邊搜索的速度不影響(

索引會先存在內存中,內存不足再寫入磁盤,還有隊列空閒時把索引寫入硬盤)

支持的數據格式

Xml等多種格式

json

分佈式管理

zookeeper

本身維護

Sharding

沒有自動shard rebalancing的功能

Shard必須一次設置好,以後不能修改,若是要修改則須要從新創建索引

高級查詢

沒有Query DSL

有Query DSL,可以支持更加高級和複雜的查詢語法,並且還能夠以此擴展實現類sql語法的查詢

搜索

傳統搜索應用

實時搜索應用(1s的延遲)

插件

不支持插件式開發

支持插件式開發,豐富的插件庫

 

9.  在線資源

Elasticsearch: 權威指南 

Elasticsearch 參考手冊

https://www.elastic.co/guide/

中文社區

Java Api

相關文章
相關標籤/搜索