Elasticsearch入門教程


1.  什么是 Elasticsearch

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

2.  安裝

  • Elasticsearch 需要 Java 8 環境

2.1. Windows上運行ElasticSearch

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

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

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


見到xxxx started,那么就是啟動完成了,打開瀏覽器輸入http:\\localhost:9200http:\\127.0.0.1:9200,如果出現以下文本證明啟動成功了。

{
  "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。

network.host: 0.0.0.0

上面代碼中,設成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是否安全成功。

解壓壓縮包,切換到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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM