• 企业级搜索elasticsearch应用02-elasticsearch搜索


    一 。使用命令搜索

      1》uri搜索(参考https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html)

         uri搜索表示将查询以及操作的动作置于uri参数中 
       为了方便搜索 添加测试数据(/root/my.json)

    {"index":{"_id":"1"}}
    {"id":"1","country":"美国","provice":"加利福尼亚州","city":"旧金山","age":"30","name":"John","desc":"John is come from austrina  John,s Dad is Johh Super"}  
    {"index":{"_id":"2"}}
    {"id":"2","country":"美国","provice":"加利福尼亚州","city":"好莱坞","age":"40","name":"Mike","desc":"Mike is come from austrina  Mike,s Dad  is Mike Super"}  
    {"index":{"_id":"3"}}
    {"id":"3","country":"美国","provice":"加利福尼亚州","city":"圣地牙哥","age":"50","name":"Cherry","desc":"Cherry is come from austrina  Cherry,s Dad  is Cherry Super"}  
    {"index":{"_id":"4"}}
    {"id":"4","country":"美国","provice":"德克萨斯州","city":"休斯顿","age":"60","name":"Miya","desc":"Miya is come from austrina  Miya,s Dad  is Miya Super"}  
    {"index":{"_id":"5"}}
    {"id":"5","country":"美国","provice":"德克萨斯州","city":"大学城","age":"70","name":"fubos","desc":"fubos is come from austrina  fubos,s Dad  is fubos Super"}  
    {"index":{"_id":"6"}}
    {"id":"6","country":"美国","provice":"德克萨斯州","city":"麦亚伦","age":"20","name":"marry","desc":"marry is come from austrina  marry,s Dad  is marry Super"}  
    {"index":{"_id":"7"}}
    {"id":"7","country":"中国","provice":"湖南省","city":"长沙市","age":"18","name":"张三","desc":"张三来自长沙市 是公务员一名"}  
    {"index":{"_id":"8"}}
    {"id":"8","country":"中国","provice":"湖南省","city":"岳阳市","age":"15","name":"李四","desc":"李四来自岳阳市 是一名清洁工"}  
    {"index":{"_id":"9"}}
    {"id":"9","country":"中国","provice":"湖南省","city":"株洲市","age":"33","name":"李光四","desc":"李光四 老家岳阳市 来自株洲 是李四的侄子"}  
    {"index":{"_id":"10"}}
    {"id":"10","country":"中国","provice":"广东省","city":"深圳市","age":"67","name":"王五","desc":"王五来自深圳市  是来自深圳的一名海关缉私精英"}  
    {"index":{"_id":"11"}}
    {"id":"11","country":"中国","provice":"广东省","city":"广州市","age":"89","name":"王冠宇","desc":"王冠宇是王五的儿子"}  
    使用bulkapi 来批量导入
    cd /root && curl -XPOST '192.168.58.147:9200/user/info/_bulk?pretty' --data-binary @my.json

    可以使用 _search api来实现文档的搜索 比如 (q=查询的列:值)

    [root@node1 ~]# curl -XGET 'http://192.168.58.147:9200/_search?q=name=marry&pretty'
    {
      "took" : 42,
      "timed_out" : false,
      "_shards" : {
        "total" : 10,
        "successful" : 10,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : 1,
        "max_score" : 1.6127073,
        "hits" : [
          {
            "_index" : "user",
            "_type" : "info",
            "_id" : "6",
            "_score" : 1.6127073,
            "_source" : {
              "id" : "6",
              "country_s" : "美国",
              "provice_s" : "德克萨斯州",
              "city_s" : "麦亚伦",
              "age_i" : "20",
              "name_s" : "marry",
              "desc_s" : "marry is come from austrina  marry,s Dad  is marry Super"
            }
          }
        ]
      }
    }
     查询所有用户索引中 年龄是50的
    curl -XGET 'http://192.168.58.147:9200/user/_search?q=age:50&pretty'
    查询所有用户索引库中 用户信息类型 用户资产类型 年龄是30的 多个索引或者多个类型使用,隔开
    curl -XGET 'http://192.168.58.147:9200/student/info,money/_search?q=age:30&pretty'
    查询所有索引库中(_all)类型是info的年龄是30的用户
    curl -XGET 'http://192.168.58.147:9200/_all/info/_search?q=age:30&pretty'
    使用from指定从第几条开始查 size返回的结果数  默认from=0 size=10
    curl -XGET 'http://192.168.58.147:9200/user/_search?q=age:30&from=0&size=2&pretty'

    常用的查询参数如下:

    Name Description
    q 表示查询字符串
    df 在查询中,当没有定义字段的前缀的情况下的默认字段前缀
    analyzer 当分析查询字符串时,分析器的名字
    default_operator 被用到的默认操作,有ANDOR两种,默认是OR
    explain 对于每一个命中(hit),对怎样得到命中得分的计算给出一个解释
    _source 将其设置为false,查询就会放弃检索_source字段。你也可以通过设置_source_include_source_exclude检索部分文档
    fields 命中的文档返回的字段
    sort 排序执行。可以以fieldNamefieldName:asc或者fieldName:desc的格式设置。fieldName既可以是存在的字段,也可以是_score字段。可以有多个sort参数
    track_scores 当排序的时候,将其设置为true,可以返回相关度得分
    timeout 默认没有timeout
    from 默认是0
    size 默认是10
    search_type 搜索操作执行的类型,有dfs_query_then_fetchdfs_query_and_fetchquery_then_fetchquery_and_fetchcountscan几种,默认是query_then_fetch
    lowercase_expanded_terms terms是否自动小写,默认是true
    analyze_wildcard 是否分配通配符和前缀查询,默认是false
    terminate_after The maximum number of documents to collect for each shard, upon reaching which the query execution will terminate early. If set, the response will have a boolean field terminated_early to indicate whether the query execution has actually terminated_early. Defaults to no terminate_after.

    指定使用中文名查询时 都无法查询数据 应该是分词器 分词的问题

    curl -XGET 'http://192.168.58.147:9200/user/info/_search?q=name=张&pretty'   
    curl -XGET 'http://192.168.58.147:9200/user/info/_search?q=name=张三&pretty'   
    
    测试默认分词器的分词功能
    [root@node1 ~]# curl -XPOST  'http://192.168.58.147:9200/_analyze?pretty' -d '
    > {
    >   "tokenizer": "standard",
    >   "text":      "我是饺子"
    > }';
    {
      "tokens" : [
        {
          "token" : "我",
          "start_offset" : 0,
          "end_offset" : 1,
          "type" : "<IDEOGRAPHIC>",
          "position" : 0
        },
        {
          "token" : "是",
          "start_offset" : 1,
          "end_offset" : 2,
          "type" : "<IDEOGRAPHIC>",
          "position" : 1
        },
        {
          "token" : "饺",
          "start_offset" : 2,
          "end_offset" : 3,
          "type" : "<IDEOGRAPHIC>",
          "position" : 2
        },
        {
          "token" : "子",
          "start_offset" : 3,
          "end_offset" : 4,
          "type" : "<IDEOGRAPHIC>",
          "position" : 3
        }
      ]
    }

     既然是逐个分词 q=name:张 应该可以查出来啊 奇怪 后来想到http协议有可能在url上带参数 中文乱码 不使用url方式 使用requestbody的方式试试

    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query" : {
            "term" : { "name" : "三" }
        }
    }'
     发现这样搜索 就是搜索张或者三都能出结果 输入张三无法出结果  确实是standard分词器的特点
    实际上 张三 就是一个词  这里推荐使用ik分词器的分词 分成的词 具有一定的意义(比如我是中国人  拆分成 我 是 中国人  中国等有意义的词)

    设置ik分词器 (IK插件地址 https://github.com/medcl/elasticsearch-analysis-ik)

    我这里5.6.4的es下载对应 5.6.4的ik
    cd /home/es/elasticsearch-5.6.4 &&
        ./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v5.6.4/elasticsearch-analysis-ik-5.6.4.zip
    安装完成后  检查plugins目录
    [es@node1 elasticsearch-5.6.4]$ cd plugins/
    [es@node1 plugins]$ ll
    total 4
    drwxr-xr-x 2 es es 4096 Dec  5 18:49 analysis-ik
    重启 elasticsearch
     ./elasticsearch -Ecluster.name=my_cluster_name -Enode.name=my_node_name -Enetwork.host=192.168.58.147
    ik 带有两个分词器 
    ik_max_word :会将文本做最细粒度的拆分;尽可能多的拆分出词语 
    ik_smart:会做最粗粒度的拆分;已被分出的词语将不会再次被其它词语占有 
    测试 
    [es@node1 plugins]$ curl -XGET 'http://192.168.58.147:9200/_analyze?pretty&analyzer=ik_max_word' -d '我是中国人'
    {
      "tokens" : [
        {
          "token" : "我",
          "start_offset" : 0,
          "end_offset" : 1,
          "type" : "CN_CHAR",
          "position" : 0
        },
        {
          "token" : "是",
          "start_offset" : 1,
          "end_offset" : 2,
          "type" : "CN_CHAR",
          "position" : 1
        },
        {
          "token" : "中国人",
          "start_offset" : 2,
          "end_offset" : 5,
          "type" : "CN_WORD",
          "position" : 2
        },
        {
          "token" : "中国",
          "start_offset" : 2,
          "end_offset" : 4,
          "type" : "CN_WORD",
          "position" : 3
        },
        {
          "token" : "国人",
          "start_offset" : 3,
          "end_offset" : 5,
          "type" : "CN_WORD",
          "position" : 4
        }
      ]
    }
    [es@node1 plugins]$ curl -XGET 'http://192.168.58.147:9200/_analyze?pretty&analyzer=ik_smart' -d '我是中国人'        
    {
      "tokens" : [
        {
          "token" : "我",
          "start_offset" : 0,
          "end_offset" : 1,
          "type" : "CN_CHAR",
          "position" : 0
        },
        {
          "token" : "是",
          "start_offset" : 1,
          "end_offset" : 2,
          "type" : "CN_CHAR",
          "position" : 1
        },
        {
          "token" : "中国人",
          "start_offset" : 2,
          "end_offset" : 5,
          "type" : "CN_WORD",
          "position" : 2
        }
      ]
    }
    删除索引user  重新创建索引 user
     curl -XDELETE 'http://192.168.58.147:9200/user?pretty'  
     curl -XPUT 'http://192.168.58.147:9200/user?pretty' -d '{
        "settings" : {
            "analysis" : {
                "analyzer" : {
                    "ik" : {
                        "tokenizer" : "ik_max_word"
                    }
                }
            }
        },
        "mappings" : {
            "info" : {
                "dynamic" : true,
                "properties" : {
                    "name" : {
                        "type" : "string",
                        "analyzer" : "ik_max_word"
                    },"desc" : {
                        "type" : "string",
                        "analyzer" : "ik_max_word"
                    }
                }
            }
        }
    }';
    
    上面的创建 表示设置 user的分词器是ik  mapping用于设置 类型和属性的类型 以及他的分词器
    info类型下的name_s和desc_s使用分词器
    再次进入/root导入之前的数据文件
    cd /root && curl -XPOST '192.168.58.147:9200/user/info/_bulk?pretty' --data-binary @my.json

    测试分词器的效果 发现张 无法查询了 张三才能查询

    [root@node1 ~]# curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query" : {
            "term" : { "name" : "张" }  
        }
    }';
    {
      "took" : 22,
      "timed_out" : false,
      "_shards" : {
        "total" : 5,
        "successful" : 5,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : 0,
        "max_score" : null,
        "hits" : [ ]
      }
    }

    2》请求体搜索

    》》term 词查询
     中文搜索只能使用请求体搜索 否则无法搜索 所以一般搜索都是使用请求体 简单测试使用uri搜索 一般请求体中使用dsl语言 比如
    查询所有数据

    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query" : {
    
        }
    }';
    查询包含词 name字段=三的

    "query" : {
            "term" : { "name" : "三" }
        }
    和query同级 支持以下参数

    Name Description
    timeout 默认没有timeout
    from 默认是0
    size 默认是10
    search_type 搜索操作执行的类型,有dfs_query_then_fetchdfs_query_and_fetchquery_then_fetchquery_and_fetchcountscan几种,默认是query_then_fetch
    query_cache ?search_type=count时,查询结果是否缓存
    terminate_after The maximum number of documents to collect for each shard, upon reaching which the query execution will terminate early. If set, the response will have a boolean field terminated_early to indicate whether the query execution has actually terminated_early. Defaults to no terminate_after.

    from和size 设置分页 order设置排序(注意请求体的参数不要用tab键代替空格 否则出错)

    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "from":0,
      "size":5,
      "sort":[
    	{"_score":{"order":"desc"}},
    	{"age":{"order":"desc"}}
      ],
      "query" : {
            "term" : { "desc" : "来自" }
        }
    }';
    按照每个document的得分降序 得分相同的数据再按照age降序排序 我之前导入数据时 age使用的""表示是字符串 一般都会抛出异常
    "reason": "Fielddata is disabled on text fields by default. Set fielddata=true on 
    表示默认的字符串 不允许排序或者聚合 应该将fielddata设置为true 修改之前创建的映射 添加一个age将fielddata设置为true
    "properties" : {
                    "name" : {
                        "type" : "string",
                        "analyzer" : "ik_max_word"
                    },"desc" : {
                        "type" : "string",
                        "analyzer" : "ik_max_word"
                    },"age" : {
                        "type" : "string",
                         "fielddata" : true 
                    }
                }
    或者 type改成integer
    "age" : {
                        "type" : "integer"
             }
    _source指定显示哪些列
    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query" : {
            "term" : { "desc" : "来自" }
        },
        "_source":["name", "desc"]
    }';

    》》terms 词查询

      terms和term功能类似 允许搜索多个词

    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query": {
         "terms" : {
           "desc" : ["来自","com"]
         }
       }
    }';

    》》match查询

      对比term和match区别
    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query" : {
           "term" : { "desc" : "李 来自" }
        }
    }';
    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query" : {
           "match" : { "desc" : "李 来自" }
        }
    }';
    
    term会认为 李 来自是一个词 去匹配 所有查不到任何数据
    match 将包含李 和来自 两个词的数据合并查询
    还有另外一个match_phrase和term是一样的认为是一个词
    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query": { "match_phrase": { "desc" : "李 来自" } }
    }'
    》》bool查询
    bool查询可以组合查询 比如 must必须两个条件都满足 必须有李和来自两个词
    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query": {
        "bool": {
          "must": [
            { "match": { "desc": "李" } },
            { "match": { "desc": "来自" } }
          ]
        }
      }
    }'	
    should 出现任意一个词即可
    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query": {
        "bool": {
          "should": [
            { "match": { "desc": "李" } },
            { "match": { "desc": "来自" } }
          ]
        }
      }
    }';	
    must_not必须没有某些词
    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query": {
        "bool": {
          "must_not": [
            { "match": { "desc": "李" } },
            { "match": { "desc": "来自" } }
          ]
        }
      }
    }';	
    也可以组合使用 必须出现词李 不能出现词 来自
    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query": {
        "bool": {
          "must_not": [
            { "match": { "desc": "李" } }
          ],
    	  "must":[{ "match": { "desc": "来自" } }]
        }
      }
    }';		

    》》regexp正则查询

     支持正则匹配模式 例如

    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query" : {
           "regexp" : { "desc" : "李.*" }
        }
    }';
    》》prefix前缀查询
     以什么词开头 必须是一个词
    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query" : {
           "prefix" : { "desc" : "李" }
        }
    }';

    》》multi_match多字段查询

    多个字段等于同一个词

    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query": {
         "multi_match" : {
           "query" : "李" ,
    	   "fields":["name","desc"]
         }
       }
    }';
    》》range范围过滤

    范围操作符包含:

    • gt :: 大于
    • gte:: 大于等于
    • lt :: 小于
    • lte:: 小于等于
    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query": {
         "range" : {
           "age" : {"gt":20}
         }
       }
    }';
    假设需要判断  age>=20 and age<=30
    使用range
    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query": {
         "range" : {
           "age" : {"gte":20,"lte":"30"}
         }
       }
    }';
    可是使用bool
    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query":{
      "bool":{
       "must": {
         "range" : {
           "age" : {"gte":20}
          }
        },
       "must": {
         "range" : {
           "age" : {"lte":30}
          }
         }
       }
       }
    }';
    》》exists 和 missing 过滤

      exists 和 missing 过滤可以用于查找文档中是否包含指定字段或没有某个字段

    比如 查询所有带有age字段的doc

    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
        "query":{
    	   "exists":{"field":"age"}
    	}
    }';	
    查询所有没有 age字段的doc
    miising已经过期 替代的是使用bool+exists
    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query":{
      "bool":{
       "must_not": {
         "exists" : {
           "field":"age"
          }
        }
       }
       }
    }';		

    3》过滤

          每次的搜索返回的结果中都有一个_score的字段  这个得分是指定的搜索查询匹配程度的一个相对度量。得分越高,文档越相关,
    得分越低文档的相关度越低。

    Elasticsearch中的所有的查询都会触发相关度得分的计算。对于那些我们不需要相关度得分的场景下,Elasticsearch以过滤器的形式提供了另一种查询功能。过滤器在概念上类似于查询,但是它们有非常快的执行速度,这种快的执行速度主要有以下两个原因:

        过滤器不会计算相关度的得分,所以它们在计算上更快一些
        过滤器可以被缓存到内存中,这使得在重复的搜索查询上,其要比相应的查询快出许多。
    比如查询是否存在字段age的doc 可以用query 也可以使用过滤  过滤放在bool中
    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query":{
      "bool":{
       "filter": {
         "exists" : {
           "field":"age"
          }
        }
       }
       }
    }';	
    返回的结果中 _score都为0 比如
    {
            "_index" : "user",
            "_type" : "info",
            "_id" : "7",
            "_score" : 0.0,
            "_source" : {
              "id" : "7",
              "country" : "中国",
              "provice" : "湖南省",
              "city" : "长沙市",
              "age" : "18",
              "name" : "张三",
              "desc" : "张三来自长沙市 是公务员一名"
            }
          }
    4》聚合

     默认数字类型 比如 integer float long都可以直接聚合 如果是字符串需要聚合 必须设置属性 fielddata=true  假设我使用国家进行聚合(group by)
    首先修改 mapping 添加映射(删除索引 重建 重新导入数据)

                   "country" : {
                        "type" : "string",
                        "analyzer" : "ik_max_word",
                        "fielddata":true
                    },"provice" : {
                        "type" : "string",
                        "analyzer" : "ik_max_word",
                        "fielddata":true
                    },"city" : {
                        "type" : "string",
                        "analyzer" : "ik_max_word",
                        "fielddata":true
                    }
    
    

    
    执行简单的聚合 (按某个字段分组 每个分组有多少个元素) 注意指定分词器 否则 逐个单词来分组
    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "size": 0,
      "aggs": {
        "group_by_country": {
          "terms": {
            "field": "country"
          }
        }
      }
    }';
    最后聚合结果为:

     "aggregations" : {
        "group_by_country" : {
          "doc_count_error_upper_bound" : 0,
          "sum_other_doc_count" : 0,
          "buckets" : [
            {
              "key" : "美国",
              "doc_count" : 6
            },
            {
              "key" : "中国",
              "doc_count" : 5
            }
          ]
        }
      }
    类似于sql语句
    SELECT country as key,COUNT(*) as doc_count from user_info GROUP BY country ORDER BY COUNT(*) DESC
    上面的group_by_country是给当前分组取一个名字 可以多个分组 下面结果会出现两个分组结果 互不影响
    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "size": 0,
      "aggs": {
        "group_by_country": {
          "terms": {
            "field": "country"
          }
        },
        "group_by_provice": {
          "terms": {
            "field": "provice"
          }
        }
      }
    }';
    上面size:0表示只是获取分组的结果  类似于solr中的facets

    如果设置了size:数字  返回结果中 还会带出具体分组的具体数据 类似于solr的聚合

    es的聚合支持嵌套 比如 按国家分组后  再按城市分组 (安装国家分组 各个分组内部的数据 再按照城市分组 )

    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "size": 0,
      "aggs": {
        "group_by_country": {
          "terms": {
            "field": "country"
          },
          "aggs":{
            "group_by_age":{
              "terms":{
                 "field":"city"
               }
            }
    	  }
        }
      }
    }';
    也可以在嵌套的聚合中使用聚合函数获取平均值 最大值 或者最小值
    分组获取每组平均年龄 按照平均年龄大到小排序  支持max min  sum 等聚合
    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "size": 0,
      "aggs": {
        "group_by_country": {
          "terms": {
            "field": "country"
          },
          "aggs":{
            "avg_age":{
              "avg":{
                 "field":"age"
               }
            }
    	  }
        }
      }
    }';
    支持 按照范围值进行分组 比如按照国家分组后 按照每个国家的年龄段分组
    curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "size": 0,
      "aggs": {
        "group_by_country": {
          "terms": {
            "field": "country"
          },
          "aggs":{
            "group_by_age_range":{
              "range": {
    			"field": "age",
    			"ranges": [
    			  {
    				"from": 10,
    				"to": 20
    			  },
    			  {
    				"from": 20,
    				"to": 40
    			  },
    			  {
    				"from": 40,
    				"to": 100
    			  }
    			]
    		  }
            }
    	  }
        }
      }
    }';	
    
    

    二 。使用命令搜索

    java操作 搜索的api

    package es;
    
    import java.net.InetAddress;
    import java.net.UnknownHostException;
    import java.util.List;
    
    import org.elasticsearch.action.search.SearchResponse;
    import org.elasticsearch.client.transport.TransportClient;
    import org.elasticsearch.common.settings.Settings;
    import org.elasticsearch.common.transport.InetSocketTransportAddress;
    import org.elasticsearch.index.query.QueryBuilders;
    import org.elasticsearch.search.SearchHit;
    import org.elasticsearch.search.aggregations.AggregationBuilders;
    import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
    import org.elasticsearch.search.aggregations.bucket.terms.StringTerms.Bucket;
    import org.elasticsearch.search.aggregations.metrics.avg.Avg;
    import org.elasticsearch.search.sort.SortOrder;
    import org.elasticsearch.transport.client.PreBuiltTransportClient;
    
    /**
     * 之前的 /user/info数据为例
     * @author jiaozi
     *
     */
    public class Search {
    	/**
    	 * 查询所有的 的doc
    	 * [root@node1 ~]# curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    > {
    >   "query":{}
    > }'
    {
      "hits" : {
        "total" : 1,
        "max_score" : 0.5377023,
        "hits" : [
          {
            "_index" : "user",
            "_type" : "info",
            "_id" : "7",
            "_score" : 0.5377023,
            "_source" : {
              "id" : "7",
              "country" : "中国",
              "provice" : "湖南省",
              "city" : "长沙市",
              "age" : "18",
              "name" : "张三",
              "desc" : "张三来自长沙市 是公务员一名"
            }
          }
        ]
      }
    }
    上面的结果是  hits里有多个hits 代码也是一样  hits里有source
    	 */
    	public static void search(){
    		SearchResponse searchResponse = client.prepareSearch("user")
    			.setTypes("info")
    			.addSort("age", SortOrder.ASC)
    			.setFrom(0)
    			.setSize(5)
    			.get();
    		SearchHit[] hits = searchResponse.getHits().getHits();
    		for (int i = 0; i < hits.length; i++) {
    			System.out.println(hits[i].getSource());
    		}
    	}
    	/**
    	 * curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "query" : {
            "term" : { "desc" : "来自" }
        },
        "_source":["name", "desc"]
    }';
    	 */
    	public static void searchTerms(){
    		SearchResponse searchResponse = client.prepareSearch("user")
    			.setTypes("info")
    			.addSort("age", SortOrder.ASC)
    			//QueryBuilders可以指定其他 比如 match或者match_phase或者 regexp 或者prefix或者其他
    			.setQuery(QueryBuilders.termQuery("desc", "来自")) //搜索 有得分
    			//.setQuery(QueryBuilders.rangeQuery("age").lte(30)) //范围查询
    			//.setQuery(QueryBuilders.regexpQuery("desc", "来自"))//正则
    			//.setQuery(QueryBuilders.prefixQuery("desc", "张三"))//前缀
    			//.setQuery(QueryBuilders.matchQuery("desc", "张三 来自"))//match
    			//.existsQuery("desc")  //exists 是否存在字段
    			//.setPostFilter(QueryBuilders.termQuery("desc", "来自")) //过滤没得分
    			.setFrom(0)
    			.setSize(5)
    			.get();
    		SearchHit[] hits = searchResponse.getHits().getHits();
    		for (int i = 0; i < hits.length; i++) {
    			System.out.println(hits[i].getSource());
    		}
    	}
    	/**
    	 * 等价于 
    	 * curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    		{
    		  "query":{
    		  "bool":{
    		   "must": {
    		     "range" : {
    		       "age" : {"gte":20}
    		      }
    		    },
    		   "must": {
    		     "range" : {
    		       "age" : {"lte":30}
    		      }
    		     }
    		   }
    		   }
    		}';
    	 */
    	public static void searchBool(){
    		SearchResponse searchResponse = client.prepareSearch("user")
    				.setTypes("info")
    				.setQuery(QueryBuilders
    						.boolQuery()
    						.must(QueryBuilders.rangeQuery("age").lte(40))
    						.must(QueryBuilders.rangeQuery("age").gte(20))
    						//.mustNot(queryBuilder)
    						//.should(queryBuilder)
    						)
    				.get();
    		SearchHit[] hits = searchResponse.getHits().getHits();
    		for (int i = 0; i < hits.length; i++) {
    			System.out.println(hits[i].getSource());
    		}
    	}
    	/**
    	 * 聚合 
    	 * curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    		{
    		  "size": 0,
    		  "aggs": {
    		    "group_by_country": {
    		      "terms": {
    		        "field": "country"
    		      }
    		    }
    		  }
    		}';
    	 */
    	public static void aggs(){
    		SearchResponse searchResponse = client.prepareSearch("user")
    				.addAggregation(AggregationBuilders.terms("group_by_country").field("country"))
    				.setSize(4)
    				.get();
    		StringTerms terms = searchResponse.getAggregations().get("group_by_country");
    		List<Bucket> buckets = terms.getBuckets();
    		for (int i = 0; i < buckets.size(); i++) {
    			Bucket bucket = buckets.get(i);
    			System.out.println(bucket.getKey()+"----"+bucket.getDocCount());
    		}
    		SearchHit[] hits = searchResponse.getHits().getHits();
    		for (int i = 0; i < hits.length; i++) {
    			System.out.println(hits[i].getSource());
    		}
    	}
    	/**
    	 * curl -XPOST '192.168.58.147:9200/user/_search?pretty' -d '
    {
      "size": 0,
      "aggs": {
        "group_by_country": {
          "terms": {
            "field": "country"
          },
          "aggs":{
            "avg_age":{
              "avg":{
                 "field":"age"
               }
            }
    	  }
        }
      }
    }';
    	 */
    	public static void aggsAvgs(){
    		SearchResponse searchResponse = client.prepareSearch("user")
    				.addAggregation(AggregationBuilders
    						.terms("group_by_country")
    						.field("country")
    						.subAggregation(AggregationBuilders.avg("avg_age").field("age"))
    						)
    				.get();
    		StringTerms terms = searchResponse.getAggregations().get("group_by_country");
    		List<Bucket> buckets = terms.getBuckets();
    		for (int i = 0; i < buckets.size(); i++) {
    			Bucket bucket = buckets.get(i);
    			Avg st=bucket.getAggregations().get("avg_age");
    			System.out.println(bucket.getKey()+"----"+bucket.getDocCount());
    			System.out.println(st.getValue());
    		}
    		
    	}
    	
    	public static void main(String[] args) {
    		aggsAvgs();
    	}
    	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;
    	}
    }
    


    
                
    
  • 相关阅读:
    122. 买卖股票的最佳时机 II-leetcode
    SQL优化
    《C++ Primer Plus》读书笔记之十二—C++中的代码重用
    《C++ Primer Plus》读书笔记之十一—类继承
    《C++ Primer Plus》读书笔记之十—类和动态内存分配
    《C++ Primer Plus》读书笔记之九—使用类
    《C++ Primer Plus》读书笔记之八—对象和类
    一道算法题-换钱
    《C++ Primer Plus》读书笔记之七—内存模型和名称空间
    《C++ Primer Plus》读书笔记之六—函数探幽
  • 原文地址:https://www.cnblogs.com/liaomin416100569/p/9331156.html
Copyright © 2020-2023  润新知