zoukankan      html  css  js  c++  java
  • 企业级搜索elasticsearch应用01-单机安装和索引文档操作

    一 。elasticsearch简介

         elasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful 

    web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。

    设计用于云计算 能够达到实时搜索,稳定,可靠,快速安装使用方便

    集群(cluster)

    一个集群就是由一个或多个节点组织在一起, 它们共同持有你全部的数据, 并一起提供索引和搜索功能。 一个集群由一个唯一的名字标识, 这个名字默认就是“elasticsearch”。 这个名字很重要, 因为一个节点只能通过指定某个集群的名字,来加入这个集群。在生产环境中显式地设定这个名字是一个好习惯,但是使用默认值来进行测试/开发也是不错的。

    注意,一个集群中只包含一个节点是合法的。另外,你也可以拥有多个集群,集群以名字区分。

    节点(node)

    一个节点是你集群中的一个服务器,作为集群的一部分,它存储你的数据,参与集群的索引和搜索功能。 和集群类似, 一个节点也是由一个名字来标识的, 默认情况下, 这个名字是一个随机的Marvel角色的名字,这个名字会在节点启动时分配给它。这个名字对于管理工作来说很重要,因为在这个管理过程中,你会去确定网络中的哪些 服务器对应于Elasticsearch集群中的哪些节点。

    一个节点可以通过配置集群名称的方式来加入一个指定的集群。 默认情况下,每个节点都会被安排加入到一个叫做“elasticsearch”的集群中,这意味着,如果你在你的网络中启动了若干个节点, 并假定它们能够相互发现彼此,它们将会自动地形成并加入到一个叫做“elasticsearch” 的集群中。

    在一个集群里可以拥有任意多个节点。而且,如果当前你的网络中没有运行任何Elasticsearch节点,这时启动一个节点,会默认创建并加入一个叫做“elasticsearch”的单节点集群。

    索引(index)

    一个索引就是一个拥有相似特征的文档的集合。比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引。一个索引由一个名字来 标识(必须全部是小写字母的),并且当我们要对这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。在一个集群中,你能够创建任意多个索引。

    类型(type)

    在一个索引中,你可以定义一种或多种类型。一个类型是你的索引的一个逻辑上的分类/分区,其语义完全由你来定。通常,会为具有一组相同字段的文档定义一个类型。比如说,我们假设你运营一个博客平台 并且将你所有的数据存储到一个索引中。在这个索引中,你可以为用户数据定义一个类型,为博客数据定义另一个类型,当然,也可以为评论数据定义另一个类型。

    文档(document)

    一个文档是一个可被索引的基础信息单元。比如,你可以拥有某一个客户的文档、某一个产品的一个文档、某个订单的一个文档。文档以JSON格式来表示,而JSON是一个到处存在的互联网数据交互格式。

    在一个index/type里面,你可以存储任意多的文档。注意,一个文档物理上存在于一个索引之中,但文档必须被索引/赋予一个索引的type。

    分片和复制(shards and replicas)

    一个索引可以存储超出单个结点硬件限制的大量数据。比如,一个具有10亿文档的索引占据1TB的磁盘空间,而任一节点可能没有这样大的磁盘空间来存储或者单个节点处理搜索请求,响应会太慢。

    为了解决这个问题,Elasticsearch提供了将索引划分成多片的能力,这些片叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引” 可以被放置到集群中的任何节点上。

    分片之所以重要,主要有两方面的原因:

    • 允许你水平分割/扩展你的内容容量
    • 允许你在分片(位于多个节点上)之上进行分布式的、并行的操作,进而提高性能/吞吐量

    至于一个分片怎样分布,它的文档怎样聚合回搜索请求,是完全由Elasticsearch管理的,对于作为用户的你来说,这些都是透明的。

    在一个网络/云的环境里,失败随时都可能发生。在某个分片/节点因为某些原因处于离线状态或者消失的情况下,故障转移机制是非常有用且强烈推荐的。为此, Elasticsearch允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制。

    复制之所以重要,有两个主要原因:

    • 在分片/节点失败的情况下,复制提供了高可用性。复制分片不与原/主要分片置于同一节点上是非常重要的。
    • 因为搜索可以在所有的复制上并行运行,复制可以扩展你的搜索量/吞吐量

    总之,每个索引可以被分成多个分片。一个索引也可以被复制0次(即没有复制) 或多次。一旦复制了,每个索引就有了主分片(作为复制源的分片)和复制分片(主分片的拷贝)。 分片和复制的数量可以在索引创建的时候指定。在索引创建之后,你可以在任何时候动态地改变复制的数量,但是你不能再改变分片的数量。

    默认情况下,Elasticsearch中的每个索引分配5个主分片和1个复制。这意味着,如果你的集群中至少有两个节点,你的索引将会有5个主分片和另外5个复制分片(1个完全拷贝),这样每个索引总共就有10个分片。


    二 。elasticsearch单机安装

       单机环境  192.168.58.147
     1》添加普通用户
       es 不允许使用root账号 运行 必须添加一个账号

    [root@node1 bin]# groupadd es
    [root@node1 bin]# useradd es -g es
    [root@node1 bin]# passwd es
    2》安装es
      选择版本 5.6.4(https://www.elastic.co/downloads/past-releases/elasticsearch-5-6-4)
      下载es
    wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.6.4.tar.gz
      解压es(解压在/root下) 
     tar zxvf elasticsearch-5.6.4.tar.gz 
    将es目录拷贝到/home/es下 
    [root@node1 ~]# mv elasticsearch-5.6.4 /home/es/
    修改elasticesearch主目录的拥有者为es
    [root@node1 ~]# cd /home/es
    [root@node1 es]# ll
    total 0
    drwxr-xr-x 8 root root 134 Dec  4 17:31 elasticsearch-5.6.4
    [root@node1 es]# chown -R es:es .
    切换到 es用户下
    [root@node1 es]# su - es
    进入elasticsearch的bin目录
    启动 es(指定集群名和当前的节点名称)
    [es@node1 bin]$ ./elasticsearch -Ecluster.name=my_cluster_name -Enode.name=my_node_name
    [2017-12-04T18:11:01,606][INFO ][o.e.n.Node               ] [my_node_name] initializing ...
    [2017-12-04T18:11:02,718][INFO ][o.e.e.NodeEnvironment    ] [my_node_name] using [1] data paths, mounts [[/ (rootfs)]], net usable_space [72.5gb], net total_space [77.6gb], spins? [unknown], types [rootfs]
    [2017-12-04T18:11:02,719][INFO ][o.e.e.NodeEnvironment    ] [my_node_name] heap size [1.9gb], compressed ordinary object pointers [true]
    [2017-12-04T18:11:02,723][INFO ][o.e.n.Node               ] [my_node_name] node name [my_node_name], node ID [jRy-sXoCRP6bywdHcptjcA]
    [2017-12-04T18:11:02,724][INFO ][o.e.n.Node               ] [my_node_name] version[5.6.4], pid[6615], build[8bbedf5/2017-10-31T18:55:38.105Z], OS[Linux/3.10.0-327.el7.x86_64/amd64], JVM[Oracle Corporation/Java HotSpot(TM) 64-Bit Server VM/1.8.0_77/25.77-b03]
    [2017-12-04T18:11:02,724][INFO ][o.e.n.Node               ] [my_node_name] JVM arguments [-Xms2g, -Xmx2g, -XX:+UseConcMarkSweepGC, -XX:CMSInitiatingOccupancyFraction=75, -XX:+UseCMSInitiatingOccupancyOnly, -XX:+AlwaysPreTouch, -Xss1m, -Djava.awt.headless=true, -Dfile.encoding=UTF-8, -Djna.nosys=true, -Djdk.io.permissionsUseCanonicalPath=true, -Dio.netty.noUnsafe=true, -Dio.netty.noKeySetOptimization=true, -Dio.netty.recycler.maxCapacityPerThread=0, -Dlog4j.shutdownHookEnabled=false, -Dlog4j2.disable.jmx=true, -Dlog4j.skipJansi=true, -XX:+HeapDumpOnOutOfMemoryError, -Des.path.home=/home/es/elasticsearch-5.6.4]
    [2017-12-04T18:11:08,615][INFO ][o.e.p.PluginsService     ] [my_node_name] loaded module [aggs-matrix-stats]
    [2017-12-04T18:11:08,615][INFO ][o.e.p.PluginsService     ] [my_node_name] loaded module [ingest-common]
    [2017-12-04T18:11:08,615][INFO ][o.e.p.PluginsService     ] [my_node_name] loaded module [lang-expression]
    [2017-12-04T18:11:08,616][INFO ][o.e.p.PluginsService     ] [my_node_name] loaded module [lang-groovy]
    [2017-12-04T18:11:08,616][INFO ][o.e.p.PluginsService     ] [my_node_name] loaded module [lang-mustache]
    [2017-12-04T18:11:08,616][INFO ][o.e.p.PluginsService     ] [my_node_name] loaded module [lang-painless]
    [2017-12-04T18:11:08,616][INFO ][o.e.p.PluginsService     ] [my_node_name] loaded module [parent-join]
    [2017-12-04T18:11:08,616][INFO ][o.e.p.PluginsService     ] [my_node_name] loaded module [percolator]
    [2017-12-04T18:11:08,616][INFO ][o.e.p.PluginsService     ] [my_node_name] loaded module [reindex]
    [2017-12-04T18:11:08,616][INFO ][o.e.p.PluginsService     ] [my_node_name] loaded module [transport-netty3]
    [2017-12-04T18:11:08,617][INFO ][o.e.p.PluginsService     ] [my_node_name] loaded module [transport-netty4]
    [2017-12-04T18:11:08,617][INFO ][o.e.p.PluginsService     ] [my_node_name] no plugins loaded
    [2017-12-04T18:11:17,917][INFO ][o.e.d.DiscoveryModule    ] [my_node_name] using discovery type [zen]
    [2017-12-04T18:11:20,432][INFO ][o.e.n.Node               ] [my_node_name] initialized
    [2017-12-04T18:11:20,433][INFO ][o.e.n.Node               ] [my_node_name] starting ...
    [2017-12-04T18:11:21,374][INFO ][o.e.t.TransportService   ] [my_node_name] publish_address {127.0.0.1:9300}, bound_addresses {[::1]:9300}, {127.0.0.1:9300}
    [2017-12-04T18:11:21,424][WARN ][o.e.b.BootstrapChecks    ] [my_node_name] max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]
    [2017-12-04T18:11:21,425][WARN ][o.e.b.BootstrapChecks    ] [my_node_name] max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
    [2017-12-04T18:11:24,716][INFO ][o.e.c.s.ClusterService   ] [my_node_name] new_master {my_node_name}{jRy-sXoCRP6bywdHcptjcA}{1Z4Twn1BR3-4_hpAlHLWFQ}{127.0.0.1}{127.0.0.1:9300}, reason: zen-disco-elected-as-master ([0] nodes joined)
    [2017-12-04T18:11:24,970][INFO ][o.e.g.GatewayService     ] [my_node_name] recovered [0] indices into cluster_state
    [2017-12-04T18:11:24,976][INFO ][o.e.h.n.Netty4HttpServerTransport] [my_node_name] publish_address {127.0.0.1:9200}, bound_addresses {[::1]:9200}, {127.0.0.1:9200}
    [2017-12-04T18:11:24,977][INFO ][o.e.n.Node               ] [my_node_name] started
    有时启动报错 
    ERROR: [2] bootstrap checks failed
    [1]: max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]
    [2]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
    [2]解决修改内核参数 vm.max_map_count的参数为 262144
    [root@node1 ~]# echo vm.max_map_count=262144>>/etc/sysctl.conf
    [root@node1 ~]# sysctl -p /etc/sysctl.conf                    
    vm.max_map_count = 262144
    [1]解决 这里说 最大打开的文件 还有最大用户进程数等 都是因为默认linux对资源的限制 查看
    [root@node1 ~]# ulimit -a
    core file size          (blocks, -c) 0
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size               (blocks, -f) unlimited
    pending signals                 (-i) 7229
    max locked memory       (kbytes, -l) 64
    max memory size         (kbytes, -m) unlimited
    open files                      (-n) 1024  允许打开的最多文件数
    pipe size            (512 bytes, -p) 8
    POSIX message queues     (bytes, -q) 819200
    real-time priority              (-r) 0
    stack size              (kbytes, -s) 8192
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) 7229 最大的用户进程数
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited
    liunx允许用户自己来修改这个配置 文件位于 /etc/security/limits.conf
    [root@node1 ~]# more /etc/security/limits.conf
    # /etc/security/limits.conf
    #
    #This file sets the resource limits for the users logged in via PAM.
    #It does not affect resource limits of the system services.
    #
    #Also note that configuration files in /etc/security/limits.d directory,
    #which are read in alphabetical order, override the settings in this
    #file in case the domain is the same or more specific.
    #That means for example that setting a limit for wildcard domain here
    #can be overriden with a wildcard setting in a config file in the
    #subdirectory, but a user specific setting here can be overriden only
    #with a user specific setting in the subdirectory.
    #
    #Each line describes a limit for a user in the form:
    #
    #<domain>        <type>  <item>  <value>
    #
    #Where:
    #<domain> can be: (一般用于当前这个项对哪些用户或者用户组生效)
    #        - 指定用户名
    #        - 指定组名  语法是@组名
    #        - *表示所有的用户和用户组
    #        -  可以使用 %进行模糊匹配组 比如 %root%
    #
    #<type> can have the two values:
    #        - "soft" 设置类型是soft 表示达到这个设置的值 就报警 一般是临近 一般小于hard设置的值
    #        - "hard"  设置为hard表示到达这个设置的值就报错 更加严格
    #
    #<item> can be one of the following:
    #        - core - limits the core file size (KB)
    #        - data - max data size (KB)
    #        - fsize - maximum filesize (KB)
    #        - memlock - max locked-in-memory address space (KB)
    #        - nofile - max number of open file descriptors 最大的打开文件数
    #        - rss - max resident set size (KB)
    #        - stack - max stack size (KB)
    #        - cpu - max CPU time (MIN)
    #        - nproc - max number of processes  最大的进程数
    #        - as - address space limit (KB)
    #        - maxlogins - max number of logins for this user
    #        - maxsyslogins - max number of logins on the system
    #        - priority - the priority to run user process with
    #        - locks - max number of file locks the user can hold
    #        - sigpending - max number of pending signals
    #        - msgqueue - max memory used by POSIX message queues (bytes)
    #        - nice - max nice priority allowed to raise to values: [-20, 19]
    #        - rtprio - max realtime priority
    #
    #<domain>      <type>  <item>         <value>
    #
    
    #*               soft    core            0
    #*               hard    rss             10000
    #@student        hard    nproc           20
    #@faculty        soft    nproc           20
    #@faculty        hard    nproc           50
    #ftp             hard    nproc           0
    #@student        -       maxlogins       4
    
    # End of file
    我这里就设置为
    es hard nofile 65536
    怎么样都无法生效 最后只能在es的.bash_profile添加命令来临时设置了

    ulimit -n 65536 
    默认启动 对外监听端口9200 ip是127.0.0.1只能本机访问 指定主机ip启动
    ./elasticsearch -Ecluster.name=my_cluster_name -Enode.name=my_node_name -Enetwork.host=192.168.58.147

    关闭es (使用jps查看 kill进程)

    [es@node1 ~]$ jps
    2996 Jps
    2380 Elasticsearch
    [es@node1 ~]$ kill 2380
    启动后查看运行效果

    访问 http://192.168.58.147:9200 
    网页输出结果
    {
      "name" : "my_node_name",
      "cluster_name" : "my_cluster_name",
      "cluster_uuid" : "O8-f8Z8uRPi1yvtillYZSw",
      "version" : {
        "number" : "5.6.4",
        "build_hash" : "8bbedf5",
        "build_date" : "2017-10-31T18:55:38.105Z",
        "build_snapshot" : false,
        "lucene_version" : "6.6.1"
      },
      "tagline" : "You Know, for Search"
    }

    三 。elasticsearch操作

      Elasticsearch提供了非常全面和强大的REST API,利用这个REST API你可以同你的集群交互。下面是利用这个API,可以做的几件事情:
        查你的集群、节点和索引的健康状态和各种统计信息
        管理你的集群、节点、索引数据和元数据
       对你的索引进行 CRUD(创建、读取、更新和删除)和搜索操作
       执行高级的查询操作, 像是分页、排序、过滤、脚本编写(scripting)、小平面刻画(faceting)、聚合(aggregations)和许多其它操作

      操作rest api 在不同系统可以使用工具 比如在linux使用 curl  在window上可以使用浏览器插件 Sense(下载地址:http://download.csdn.net/download/liaomin416100569/10145990)下载后拖动到chrome内核浏览器 安装后 右上角工具栏 树状图标的打开就是
      具体操作中文文档 参考(https://endymecy.gitbooks.io/elasticsearch-guide-chinese/content/getting-started/exploring-cluster.html)
      官网英文文档参考(https://www.elastic.co/guide/en/elasticsearch/reference/current/docs.html)

    1》_cat api使用
       查看所有_cat支持的命令 (参考https://www.elastic.co/guide/en/elasticsearch/reference/current/cat.html)

    [es@node1 ~]$ curl http://192.168.58.147:9200/_cat
    =^.^=
    /_cat/allocation
    /_cat/shards
    /_cat/shards/{index}
    /_cat/master 查看master节点
    /_cat/nodes 查看所有节点
    /_cat/tasks
    /_cat/indices 查看所有索引
    /_cat/indices/{index}
    /_cat/segments
    /_cat/segments/{index}
    /_cat/count
    /_cat/count/{index}
    /_cat/recovery
    /_cat/recovery/{index}
    /_cat/health  查看健康状态
    /_cat/pending_tasks
    /_cat/aliases
    /_cat/aliases/{alias}
    /_cat/thread_pool
    /_cat/thread_pool/{thread_pools}
    /_cat/plugins
    /_cat/fielddata
    /_cat/fielddata/{fields}
    /_cat/nodeattrs
    /_cat/repositories
    /_cat/snapshots/{repository}
    /_cat/templates
    查看信息的格式 以 /_cat/nodes为例

     》》 verbose 带有列名
     这些列分表表示集群中的节点 负载机器节点名称和ip

    [root@node1 ~]# curl http://192.168.58.147:9200/_cat/nodes
    192.168.58.147 5 95 0 0.00 0.01 0.05 mdi * my_node_name
    [root@node1 ~]# curl http://192.168.58.147:9200/_cat/nodes?v
    ip             heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
    192.168.58.147            5          95   1    0.00    0.01     0.05 mdi       *      my_node_name
    》》 指定header

    》》 响应类型
        默认响应类型 text  支持 :- text  - json - smile - yaml - cbor  json是常用的类型 比如json格式输出
      

    如果是curl操作 无法格式化 可以使用 python -m json.tool进行格式化输出

    [es@node1 ~]$ curl http://192.168.58.147:9200/_cat/nodes?format=json | python -m json.tool 
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100   178  100   178    0     0   5161      0 --:--:-- --:--:-- --:--:--  5235
    [
        {
            "cpu": "2",
            "heap.percent": "5",
            "ip": "192.168.58.147",
            "load_15m": "0.05",
            "load_1m": "0.00",
            "load_5m": "0.01",
            "master": "*",
            "name": "my_node_name",
            "node.role": "mdi",
            "ram.percent": "95"
        }
    ]

    2》indices api使用

       对索引进行操作的api 常用索引操作CRUD 索引可以理解为一堆文档的集合 相似的文档可添加到同一个索引中 可以将索引理解为 mysql的数据库名
     具体操作参考(https://www.elastic.co/guide/en/elasticsearch/reference/current/indices.html)

     》》 新增索引 

    [root@node1 ~]# curl -XPUT http://192.168.58.147:9200/customer?pretty
    {
      "acknowledged" : true,
      "shards_acknowledged" : true,
      "index" : "customer"
    }
     》》 查看索引 

    [root@node1 ~]# curl -XGET http://192.168.58.147:9200/_cat/indices?v
    health status index    uuid                   pri rep docs.count docs.deleted store.size pri.store.size
    yellow open   customer urw-CVYPR2SrHPhkvRUvgg   5   1          0            0       810b           810b
    health表示健康状况是yellow 因为是单台机器没有机器做复制 pri表示主分片是5个 rep表示复制是1分 这时默认的设置 占用存储空间是810b
     》》 删除索引 

    [root@node1 ~]# curl -XDELETE http://192.168.58.147:9200/customer?pretty
    {
      "acknowledged" : true
    }
    3》文档操作(参考https://www.elastic.co/guide/en/elasticsearch/reference/current/docs.html)
      文档的结构是  curl -X<REST Verb> <Node>:<Port>/<Index>/<Type>/<ID>
     Index表示索引名称  Type表示类型 ID表示资源类型 

    下面是新增的文档的例子 索引名称是学生 类型是班级 1表示1号学生

     》》创建文档
    PUT可以是新增也可以是替换 存在就替换 不存在就新增 id是可选的如果不舒服 默认就生成一个

    [es@node1 ~]$ curl -XPUT '192.168.58.147:9200/student/g_1611/1?pretty' -d '
    > {
    >   "name": "饺子",
    >   "sex":"1",
    >   "age":"22"
    > }';
    {
      "_index" : "student",
      "_type" : "g_1611",
      "_id" : "1",
      "_version" : 1,
      "result" : "created",
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      },
      "created" : true
    }


     》》查询文档
    [es@node1 ~]$ curl -XGET '192.168.58.147:9200/student/g_1611/1?pretty'
    {
      "_index" : "student",
      "_type" : "g_1611",
      "_id" : "1",
      "_version" : 1,
      "found" : true,
      "_source" : {
        "name" : "饺子",
        "sex" : "1",
        "age" : "22"
      }
    }

    上面的查询值能一次查询一个  Multi GET API 允许同时查询多个参考(https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-multi-get.html)

    curl -XGET '192.168.58.147:9200/_mget?pretty' -d '
    {
        "docs" : [
            {
                "_index" : "student",
                "_type" : "g_1611",
                "_id" : "1"
            },
            {
                "_index" : "student",
                "_type" : "g_1611",
                "_id" : "2"
            }
        ]
    }';
    查询结果就是两个

     》》删除文档
    [es@node1 ~]$ curl -XDELETE '192.168.58.147:9200/student/g_1611/1?pretty'
    {
      "found" : true,
      "_index" : "student",
      "_type" : "g_1611",
      "_id" : "1",
      "_version" : 2,
      "result" : "deleted",
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      }
    }
    [es@node1 ~]$ curl -XGET '192.168.58.147:9200/student/g_1611/1?pretty'   
    {
      "_index" : "student",
      "_type" : "g_1611",
      "_id" : "1",
      "found" : false
    }

    可以根据条件来进行删除(具体参考https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete-by-query.html)

    curl -XPOST '192.168.58.147:9200/student/g_1611/_delete_by_query?pretty' -d '
    {
      "query": { "match": { "name": "饺子" } }
    }'
    结果是:

    [es@node1 ~]$ curl -XPOST '192.168.58.147:9200/student/g_1611/_delete_by_query?pretty' -d '
    > {
    >   "query": { "match": { "name": "饺子" } }
    > }';
    {
      "took" : 677,
      "timed_out" : false,
      "total" : 1,
      "deleted" : 1,
      "batches" : 1,
      "version_conflicts" : 0,
      "noops" : 0,
      "retries" : {
        "bulk" : 0,
        "search" : 0
      },
      "throttled_millis" : 0,
      "requests_per_second" : -1.0,
      "throttled_until_millis" : 0,
      "failures" : [ ]
    }

     》》修改文档
      方式1 类似于添加文档 -XPUT 存在就替换  如果替换的新json中如果少了某些字段 旧的也会被覆盖掉

    可以使用 POST指定_update来更新 指定了哪些列 只更新哪些列 其他列不会动

    curl -XPOST '192.168.58.147:9200/student/g_1611/1/_update?pretty' -d '
    {
      "doc":{
         "name":"饺子1"
       }
    }'
    查看发现其他列都没有变化
    [es@node1 ~]$ curl -XGET '192.168.58.147:9200/student/g_1611/1?pretty'              
    {
      "_index" : "student",
      "_type" : "g_1611",
      "_id" : "1",
      "_version" : 2,
      "found" : true,
      "_source" : {
        "name" : "饺子1",
        "sex" : "1",
        "age" : "30"
      }
    }
    》》批处理
      提供了_bulk api能够进行批量处理 是换行 作为数据解析的分隔符 所以每个json必须是一行 比如
    演示 替换 _id=1的json sex字段丢失
            更新 _id=2的数据 将age字段修改 26 其他字段不动
            删除掉 _id=4的数据 再重新创建
    模拟数据
    curl -XPUT '192.168.58.147:9200/student/g_1611/1?pretty' -d '
    {
      "name": "饺子",
      "sex":"1",
      "age":"30"
    }';
    
    curl -XPUT '192.168.58.147:9200/student/g_1611/2?pretty' -d '
    {
      "name": "cherry",
      "sex":"0",
      "age":"26"
    }';
    
    curl -XPUT '192.168.58.147:9200/student/g_1611/3?pretty' -d '
    {
      "name": "qianqian",
      "sex":"1",
      "age":"2"
    }';
    
    curl -XPUT '192.168.58.147:9200/student/g_1611/4?pretty' -d '
    {
      "name": "nono",
      "sex":"0",
      "age":"0"
    }';
    测试批处理 

    curl -XPOST '192.168.58.147:9200/_bulk?pretty' -d '
    { "index" : { "_index" : "student", "_type" : "g_1611", "_id" : "1" } }
    { "name": "饺子","age" : "30" }
    { "update" : {"_id" : "2", "_type" : "g_1611", "_index" : "student"} }
    { "doc" : {"age" : "26"} }
    { "delete" : { "_type" : "g_1611", "_index" : "student", "_id" : "4" } }
    { "create" : { "_type" : "g_1611", "_index" : "student", "_id" : "4" } }
    { "name": "nono","sex":"0","age":"0" }
    ';
    最后查询查看修改结果
    curl -XGET '192.168.58.147:9200/_mget?pretty' -d '
    {
        "docs" : [
            {
                "_index" : "student",
                "_type" : "g_1611",
                "_id" : "1"
            },
            {
                "_index" : "student",
                "_type" : "g_1611",
                "_id" : "2"
            },
            {
                "_index" : "student",
                "_type" : "g_1611",
                "_id" : "3"
            },
            {
                "_index" : "student",
                "_type" : "g_1611",
                "_id" : "4"
            }
        ]
    }';
    

    一 。JAVAAPI操作docuemnt

      里面涉及到分词器 参考 企业级搜索elasticsearch应用02设置分词器

    添加maven依赖

    <dependency>
        <groupId>org.elasticsearch</groupId>
        <artifactId>elasticsearch</artifactId>
        <version>5.6.4</version>
    </dependency>
      	<dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>transport</artifactId>
        <version>5.6.4</version>
    </dependency>
    添加测试类
    package es;
    
    import java.io.IOException;
    import java.net.InetAddress;
    import java.net.UnknownHostException;
    
    import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
    import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest;
    import org.elasticsearch.action.bulk.BulkRequestBuilder;
    import org.elasticsearch.action.delete.DeleteResponse;
    import org.elasticsearch.action.get.GetResponse;
    import org.elasticsearch.action.get.MultiGetItemResponse;
    import org.elasticsearch.action.get.MultiGetResponse;
    import org.elasticsearch.action.index.IndexRequestBuilder;
    import org.elasticsearch.action.update.UpdateRequest;
    import org.elasticsearch.client.transport.TransportClient;
    import org.elasticsearch.common.settings.Settings;
    import org.elasticsearch.common.transport.InetSocketTransportAddress;
    import org.elasticsearch.common.xcontent.XContentBuilder;
    import org.elasticsearch.common.xcontent.XContentFactory;
    import org.elasticsearch.index.query.QueryBuilders;
    import org.elasticsearch.index.reindex.BulkByScrollResponse;
    import org.elasticsearch.index.reindex.DeleteByQueryAction;
    import org.elasticsearch.transport.client.PreBuiltTransportClient;
    
    public class TestEs {
    	static TransportClient client;
    	static{
    		try {
    			client=getClient();
    		} catch (UnknownHostException e) {
    			e.printStackTrace();
    		}
    	}
    	/**
    	 * 获取客户端操作对象
    	 * @return
    	 * @throws UnknownHostException 
    	 */
    	public static TransportClient getClient() throws UnknownHostException{
    		Settings settings = Settings.builder()
    		        .put("cluster.name", "my_cluster_name")
    		        //.put("index.analysis.analyzer.default.type","ik_max_word")
    		        .build();
    		TransportClient client = new PreBuiltTransportClient(settings)
    		        .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("192.168.58.147"), 9300));
    		return client;
    	}
    	/**
    	 * Get api 通过主键获取 等价于命令
    	 * curl -XGET 'http://192.168.58.147:9200/user/card/1?pretty'
    		{
    		  "_index" : "user",
    		  "_type" : "card",
    		  "_id" : "1",
    		  "_version" : 1,
    		  "found" : true,
    		  "_source" : {
    		    "carddate" : "1990-12-22",
    		    "cardpart" : "大阪区第一工业路工业园38号18楼01室",
    		    "cardid" : "846131331212",
    		    "cardname" : "小泽",
    		    "carddesc" : "小泽是一名现任演员"
    		  }
    		}
    	 */
    	public static void getDoc(){
    		GetResponse gr=client.prepareGet("user", "card", "1").get();
    		System.out.println(gr.getVersion());
    		System.out.println(gr.getSource());
    	}
    	/**
    	 * 多个get
    	 * 
    	 */
    	public static void mgetDoc(){
    		MultiGetResponse gr=client.prepareMultiGet()
    				.add("user", "card", "1")
    				.add("user", "card", "2")
    				.get();
    		for (MultiGetItemResponse itemResponse : gr) {
    			System.out.println(itemResponse.getResponse().getSource());
    		}
    		
    	}
    	/**
    	 * 删除  等价于命令
    	 * curl -XDELETE 'http://192.168.58.147:9200/user/card/1?pretty'
    	 */
    	public static void deleteDoc(){
    		DeleteResponse  gr=client.prepareDelete("user", "card", "1").get();
    		//删除成功 输出 DELETED
    		System.out.println(gr.getResult());
    	}
    	/**
    	 * 通过查询条件删除
    	 * curl -XPOST '192.168.58.147:9200/user/card/_delete_by_query?pretty' -d '  
    		{  
    		  "query": { "match": { "cardname": "小泽" } }  
    		}'  
    	 */
    	public static void deleteByQueryDoc(){
    		BulkByScrollResponse response=DeleteByQueryAction.INSTANCE.newRequestBuilder(client)
    		 	.filter(QueryBuilders.matchQuery("cardname", "小泽"))//设置匹配的条件
    		 	.source("user")  //设置删除的索引
    		 	.get();
    		System.out.println(response.getDeleted()); 	
    	}
    	/**
    	 * 根据id修改
    	 * curl -XPOST '192.168.58.147:9200/student/g_1611/1/_update?pretty' -d '  
    		{  
    		  "doc":{  
    		     "name":"饺子1"  
    		   }  
    		}'  
    	 * @throws Exception 
    	 * 
    	 */
    	public static void updateDoc() throws Exception{
    		UpdateRequest updateRequest = new UpdateRequest();
    		updateRequest.index("user");
    		updateRequest.type("card");
    		updateRequest.id("1");
    		XContentBuilder jsonBuilder = XContentFactory.jsonBuilder();
    		updateRequest.doc(jsonBuilder
    		        .startObject()
    		            .field("cardid", "846131331213")
    		        .endObject());
    		client.update(updateRequest).get();
    		
    	}
    	/**
    	 * 该种 没有使用分词器 默认使用standard
    	 * 因为之前没有创建该索引 在插入doc自动创建
    	 * 如果之前创建过索引 并且索引 map字段使用了分词器  插入就会使用分词器
    	 *  
    	 * @throws IOException
    	 */
    	public static void putDoc() throws Exception{
    		createIndex();
    		XContentBuilder builder = XContentFactory.jsonBuilder()
    			    .startObject()
    			        .field("carddate", "1990-12-22")
    			        .field("cardpart", "大阪区第一工业路工业园38号18楼01室")
    			        .field("cardid", "846131331212")
    			        .field("cardname","小泽")
    			        .field("carddesc","小泽是一名现任演员")
    			    .endObject();
    		//参数3 数据未指定id 自动给个随机id  比如  "_id" : "AWAvSfKKMB95FFaq-s6J",
    		IndexRequestBuilder irb=client.prepareIndex("user", "card","1");
    		irb.setSource(builder);
    		irb.get();
    	}
    	/**
    	 * 批量添加
    	 * @throws Exception
    	 */
    	public void bultDoc() throws Exception{
    		createIndex();
    		BulkRequestBuilder bulkRequest = client.prepareBulk();
    		bulkRequest.add(client.prepareIndex("user", "card","2")
    				   .setSource(XContentFactory.jsonBuilder()
    			    .startObject()
    			        .field("carddate", "1990-12-22")
    			        .field("cardpart", "大阪区第一工业路工业园38号18楼01室")
    			        .field("cardid", "846131331212")
    			        .field("cardname","小泽")
    			        .field("carddesc","小泽是一名现任演员")
    			    .endObject())
    				).add(client.prepareIndex("user", "card","3")
    						   .setSource(XContentFactory.jsonBuilder()
    								    .startObject()
    								        .field("carddate", "1990-12-22")
    								        .field("cardpart", "大阪区第一工业路工业园38号18楼01室")
    								        .field("cardid", "846131331212")
    								        .field("cardname","小泽")
    								        .field("carddesc","小泽是一名现任演员")
    								    .endObject())
    									)
    		
    		
    		.get();
    	}
    	/**
    	 * 设置映射 也就是设置哪个类型下的哪个字段 类型是什么 分词器是什么 是否属于可分组排序字段	
    	 * "mappings" : {
            "类型" : {
                "dynamic" : true,
                "properties" : {
                    ""属性" : {
                        "type" : "string",
                        "analyzer" : "ik_max_word",
                        "fielddata":true
                    }
                }
            }
        }
    	 * @throws IOException 
    	 */
    	public static void createIndex() throws Exception{
    		//判断索引是否存在
    		boolean ifExistIndex=client.admin().indices().exists(new IndicesExistsRequest("user")).get().isExists();
    		if(!ifExistIndex){
    			CreateIndexRequestBuilder cirb=client.admin().indices().prepareCreate("user");
    			//构建注释上的json字符串
    			XContentBuilder builder = XContentFactory.jsonBuilder()
    					.startObject() // {
    					    .startObject("properties") //{ properties:{
    					        .startObject("cardname")    //cardname:{
    					        	.field("analyzer", "ik_max_word")//analyzer:ik_max_word
    					        	.field("type","string")
    					        	.field("fielddata",true)
    					        .endObject()
    					        .startObject("carddesc")
    					        	.field("analyzer", "ik_max_word")
    					        	.field("type","string")
    					        	.field("fielddata",true)
    					        .endObject()//}
    					    .endObject()//}
    			        .endObject();//}
    			cirb.addMapping("card", builder);
    			cirb.get();
    		}
    	}
    	
    	public static void main(String[] args) throws Exception {
    		mgetDoc();
    	}
    }
    



  • 相关阅读:
    BZOJ5321 JXOI2017加法(二分答案+贪心+堆+树状数组)
    BZOJ5089 最大连续子段和(分块)
    Codeforces 893F(主席树+dfs序)
    BZOJ5092 分割序列(贪心)
    Codeforces Round #525 Div. 2 自闭记
    364. Nested List Weight Sum II
    362. Design Hit Counter
    369. Plus One Linked List
    370. Range Addition
    366. Find Leaves of Binary Tree
  • 原文地址:https://www.cnblogs.com/liaomin416100569/p/9331157.html
Copyright © 2011-2022 走看看