zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    26_为什么我的删除刷新没有办法删除动态添加的数据呢?
    075_not in (null):这代表是什么意思呢?
    074_form表单中的value值
    025_回调函数没有遍历出数据
    073_模糊查询
    072_jsp追加与刷新数据
    071_为什么要catch return.setCode()?
    070_jstl中的三目表达式
    069_都是查询语句时得事物?
    打印周报模板
  • 原文地址:https://www.cnblogs.com/ld-swust/p/9034941.html
Copyright © 2011-2022 走看看