zoukankan      html  css  js  c++  java
  • 分布式搜索引擎Elasticsearch的查询与过滤

    一、写入

    先来一个简单的官方例子,插入的参数为-XPUT,插入一条记录。

    curl -XPUT 'http://localhost:9200/test/users/1' -d '{
        "user": "test",
        "post_date": "2009-11-15T14:12:12",
        "message": "Elastic Search"
    }'
    
    {
        "_index": "test",
        "_type": "users",
        "_id": "1",
        "_version": 2,
        "_shards": {
            "total": 2,
            "successful": 1,
            "failed": 0
        },
        "created": false
    }

    从上面的这个例子中,可以看出ES的http的服务的默认端口9200,后面的/test/users/1是这条记录的索引部分,体现了它的RESTful风格

    这三级目录分布对应了_index,_type,_id 实际上ES上存放的所有的记录都只能通过三级目录的方式找到

    • _id 字段可以是数字也可以是字符串。在执行上面的命令时ES会自动创建这些索引

    • -d 后面跟上了要插入的json格式的记录

    • -XPUT 表明这是插入一条数据,ES中叫创建一个索引

    • _version 字段,表明了当前记录的版本号,当你想这个索引重新put一条记录时,版本号会自动加一

    二、删除

    删除的http请求参数为-XDELETE,通过下面的命令可以删除这条记录:

    curl -XDELETE 'http://localhost:9200/test/users/1?pretty'
    {
      "found" : true,
      "_index" : "test",
      "_type" : "users",
      "_id" : "1",
      "_version" : 3,
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      }
    }

    删除这条记录的时候,_verison也会自动加一的。

    三、查询

    创建了一个索引后,可以通过下面的方式查询(参数-XGET)出来

    curl -XGET 'http://localhost:9200/test/users/1?pretty'       
    {
      "_index" : "test",
      "_type" : "users",
      "_id" : "1",
      "_version" : 1,
      "found" : true,
      "_source" : {
        "user" : "test",
        "post_date" : "2009-11-15T14:12:12",
        "message" : "Elastic Search"
      }
    }

    执行上面的查询命令,可以等到下面的结果,exists表示是否有查询结果,_source字段是查询到的记录。

    查询的时候,可以将_type设置成为_all,ES就会返回在_index下所有type中,第一个匹配_id的记录,还可以通过参数对返回结果继续控制,

    用fields选取返回的字段,用pretty控制返回的json格式是否更阅读友好

    curl -XGET 'http://localhost:9200/test/users/1?fields=message,user&pretty=true'
    {
      "_index" : "test",
      "_type" : "users",
      "_id" : "1",
      "_version" : 3,
      "found" : true,
      "fields" : {
        "message" : [ "Elastic Search" ],
        "user" : [ "test" ]
      }
    }

    format=yaml可以设置输入格式为YAML

    curl -XGET 'http://localhost:9200/test/users/1?fields=message,user&format=yaml' 
    ---
    _index: "test"
    _type: "users"
    _id: "1"
    _version: 1
    found: true
    fields:
      message:
      - "Elastic Search"
      user:
      - "test"

    当然ES还支持一次查询多组记录,即multi get,在URI中是使用关键字_mget,具体可以参考ES的文档multi get

    四、更新

    ES同样支持更新,但是更新的方式是通过一个提供的脚本进行的。

    ES的做法是,通过index找到相应的存放记录的节点,然后执行脚本,执行完之后,返回新的索引。实际上执行的是一个get和reindex的过程,在这个过程中,通过versioning来控制没有其它的更新操作(这个功能是0.19后可用的)。具体实现的原理应该和elasticsearch Versioning相关。

    get,reindex的含义是,ES先取出这条记录,然后根据新数据生成新记录,然后在把新记录放回到ES中(并不会覆盖老的记录)。

    首先创建一条记录

    curl -XPUT localhost:9200/test/type1/1 -d '{
        "counter" : 1,
        "tags" : ["red"]
    }'

    将counter的值加4

    curl -XPOST 'localhost:9200/test/type1/1/_update' -d '{
        "script" : "ctx._source.counter += count",
        "params" : {
            "count" : 4
        }
    }'

    也可以添加一个tag的值

    curl -XPOST 'localhost:9200/test/type1/1/_update' -d '{
        "script" : "ctx._source.tags += tag",
        "params" : {
            "tag" : "blue"
        }
    }'

    现在还支持upsert功能,即在更新的时候,如果记录没有这个key,则插入这个key,下面是一个例子,如果没有counter字段,则插入该字段:

    curl -XPOST 'localhost:9200/test/type1/1/_update' -d '{
        "script" : "ctx._source.counter += count",
        "params" : {
            "count" : 4
        },
        "upsert" : {
            "counter" : 1
        }
    }'

    关于update还有其它很多功能,可以参考ES的API update

    五、搜索

    elasticsearch的名字里面有一个search,那么主要功能也是search了。

    es的search有两种形式,一是通过URI,二是通过Requst Body。通过URI查询,即将查询的语句放入到请求的url中,例如:

    curl -XGET 'http://localhost:9200/twitter/tweet/_search?q=user:kimchy'

    第二种方式,即在查询的请求中加入一个doc

    curl -XGET 'http://localhost:9200/twitter/tweet/_search' -d '{
        "query" : {
            "term" : { "user" : "kimchy" }
        }
    }'

    query body的定义可以查看query DSL 另外两种查询方式都可以带参数,参数的含义参考URI Request和Request Body

    ES的搜索功能是可以跨index和type的,例如下面这几条命令

    curl -XGET 'http://localhost:9200/twitter/_search?q=user:kimchy'
    curl -XGET 'http://localhost:9200/twitter/tweet,user/_search?q=user:kimchy'
    curl -XGET 'http://localhost:9200/kimchy,elasticsearch/tweet/_search?q=tag:wow'
    curl -XGET 'http://localhost:9200/_all/tweet/\_search?q=tag:wow'
    curl -XGET 'http://localhost:9200/\_search?q=tag:wow'

    第一条是在所有的twitter这个index下的所有type中查找,第二条是在tweet,user这两个type中查找,第三条是在kimchy,elasticsearch这两个index的tweet这个type中查找,第四条使用了_all关键字,是在所有的index的tweet的type中查找,第五条更暴力,在所有的index和type中查找。

    查找还有其它的很多选项,sort高亮,选取返回记录的域Fields,还可以对返回的域使用一个脚本进行计算script Fields,或者对返回结果继续统计Facets,Facets的内容比较多,它支持关键词统计,范围内统计,直方图式统计,日期的直方图式统计,过滤,查询,还有记录地理位置距离的统计geo distance。 支持名字过滤Named Filters。 定义搜索类型Search Type 。例如什么Query And Fetch,Query Then Fetch。 索引加速的功能Index Boost,可以让某一个索引的权重大于另外一个。 保持上次检索的环境了结果Scroll。保留每一个命中的score值Explain。 设置命中的min_score。保留版本号Version

    Search的参数很多,我也没有一一看,不过果然是名字里面有个search,对检索的各种场景都有支持。

    当然还支持多个查询multi search,例如下面这个例子

    cat requests
    {"index" : "test"}
    {"query" : {"match_all" : {}}, "from" : 0, "size" : 10}
    {"index" : "test", "search_type" : "count"}
    {"query" : {"match_all" : {}}}
    {}
    {"query" : {"match_all" : {}}}
     
    $ curl -XGET localhost:9200/_msearch --data-binary @requests; echo

    六、DSL

    1、match

    curl -XGET 'localhost:9200/test/_search?pretty' -d'{
        "_source": ["title", "allnum"],
        "query": { 
            "match": { "title": "地铁跑酷" } 
        }
    }'
    
    {
      "took" : 2,
      "timed_out" : false,
      "_shards" : {
        "total" : 5,
        "successful" : 5,
        "failed" : 0
      },
      "hits" : {
        "total" : 1,
        "max_score" : 6.692047,
        "hits" : [ {
          "_index" : "test",
          "_type" : "external",
          "_id" : "AVicbl1W9iJMapPz5wea",
          "_score" : 6.692047,
          "_source" : {
            "title" : "地铁跑酷",
            "allnum" : 104541
          }
        } ]
      }
    } 

    显示指定字段,匹配关键字

    结果格式

    • took – 搜索用的毫秒

    • timed_out – 搜索超时时间

    • _shards – 搜索了多少个片段 成功搜索多少个 失败了多少个

    • hits – 搜索的返回结果集

    • hits.total – 结果的总数

    • hits.hits – 实际搜索返回的数组

    • _score and max_score - ignore these fields for now

    一旦es搜索返回给你 该链接就断开了 es并不会想MySQL之类的 一直维护一个连接

    更多限制条件的搜素

    curl -XGET 'localhost:9200/test/_search?pretty' -d'{
        "from": 0, 
        "size": 1,
        "_source": ["title", "allnum"],
        "query": { 
            "match": { "title": "地铁跑酷" }
        },
       "sort": { "allnum": { "order": "desc" }}
    }'
    

    2、使用should

    curl -XGET 'localhost:9200/test/_search?pretty' -d'{
        "from": 0, 
        "size": 2,
        "_source": ["title", "allnum"],
        "query": { 
            "bool": {
                "should": [
                    { "match": { "title": "地铁跑酷" } },
                    { "match": { "title": "星猫跑酷" } }
                ]
            }
        },
       "sort": { "allnum": { "order": "desc" }}
    }'
    

    3、使用must/must not

    curl -XGET 'localhost:9200/test/_search?pretty' -d'{
        "from": 0, 
        "size": 2,
        "_source": ["title", "allnum"],
        "query": { 
            "bool": {
                "must": [
                    { "match": { "title": "地铁跑酷" } },
                    { "match": { "title": "星猫跑酷" } }
                ]
            }
        },
       "sort": { "allnum": { "order": "desc" }}
    }'

    当然 must /should/must not 可以联合起来使用 

    4、过滤器

    curl -XPOST 'localhost:9200/test/_search?pretty' -d'{
        "query": { 
            "filtered": {
                "query": { 
                     "match_all": {} 
                  }, 
                 "filter": { 
                     "range": { "allumn": { "gte": 20000, "lte": 30000 } } } } 
                   }
    }'

    5、聚合

    curl  -XPOST  'localhost:9200/test/_search?pretty' -d'{
        "size": 0, 
        "aggs": { 
            "group_by_state": { 
                "terms": { "field": "state" } }
             }
    }'
    

    6、terms 过滤

    curl  -XPOST  'localhost:9200/test/_search?pretty' -d'{ 
      "query": { 
        "terms": { 
          "status": [ 
            304, 
            302 
          ] 
        } 
      } 
    }
    

    7、range 过滤

    curl  -XPOST  'localhost:9200/test/_search?pretty' -d'{ 
      "query": { 
        "range": { 
          "allnum": { 
            "gt": 1 
          } 
        } 
      } 
    }

    范围操作符包含:

    • gt :: 大于

    • gte:: 大于等于

    • lt :: 小于

    • lte:: 小于等于

    8、exists 和 missing 过滤

    exists 和 missing 过滤可以用于查找文档中是否包含指定字段或没有某个字段,类似于SQL语句中的IS_NULL条件

    { 
        "exists":   { 
            "field":    "title" 
        } 
    } 
    

    9、bool 过滤

    bool 过滤可以用来合并多个过滤条件查询结果的布尔逻辑,它包含一下操作符:

    • must :: 多个查询条件的完全匹配,相当于 and。
    • must_not :: 多个查询条件的相反匹配,相当于 not。
    • should :: 至少有一个查询条件匹配, 相当于 or。

    这些参数可以分别继承一个过滤条件或者一个过滤条件的数组:

    { 
        "bool": { 
            "must":     { "term": { "folder": "inbox" }}, 
            "must_not": { "term": { "tag":    "spam"  }}, 
            "should": [ 
                        { "term": { "starred": true   }}, 
                        { "term": { "unread":  true   }} 
            ] 
        } 
    }

    七、中文分词

    创建索引

    curl -XPUT http://localhost:9200/index
    

    创建映射

    curl -XPOST http://localhost:9200/index/fulltext/_mapping -d'
    {
        "fulltext": {
                 "_all": {
                "analyzer": "ik_max_word",
                "search_analyzer": "ik_max_word",
                "term_vector": "no",
                "store": "false"
            },
            "properties": {
                "content": {
                    "type": "string",
                    "store": "no",
                    "term_vector": "with_positions_offsets",
                    "analyzer": "ik_max_word",
                    "search_analyzer": "ik_max_word",
                    "include_in_all": "true",
                    "boost": 8
                }
            }
        }
    }'
    

    为索引添加一些内容

    curl -XPOST http://localhost:9200/index/fulltext/1 -d'
    {"content":"美国留给伊拉克的是个烂摊子吗"}
    '
    curl -XPOST http://localhost:9200/index/fulltext/2 -d'
    {"content":"公安部:各地校车将享最高路权"}
    '
    curl -XPOST http://localhost:9200/index/fulltext/3 -d'
    {"content":"中韩渔警冲突调查:韩警平均每天扣1艘中国渔船"}
    '
    curl -XPOST http://localhost:9200/index/fulltext/4 -d'
    {"content":"中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首"}
    '
    

    进行查询

    curl -XPOST http://localhost:9200/index/fulltext/_search  -d'
    {
        "query" : { "term" : { "content" : "中国" }},
        "highlight" : {
            "pre_tags" : ["<tag1>", "<tag2>"],
            "post_tags" : ["</tag1>", "</tag2>"],
            "fields" : {
                "content" : {}
            }
        }
    }
    ' 

    参考

    • http://www.elasticsearch.org

    • https://www.iwwenbo.com/elasticsearch-ik-install/

    • http://samchu.logdown.com/posts/277928-elasticsearch-chinese-word-segmentation

    • https://github.com/medcl/elasticsearch-analysis-ik

  • 相关阅读:
    专职DBA-MySQL体系结构与基本管理
    JSON
    MIME类型
    文件上传下载
    response常用的方法
    2020.11.27小记
    HTTP请求状态码
    1561. Maximum Number of Coins You Can Get
    1558. Minimum Numbers of Function Calls to Make Target Array
    1557. Minimum Number of Vertices to Reach All Nodes
  • 原文地址:https://www.cnblogs.com/chenpingzhao/p/6067350.html
Copyright © 2011-2022 走看看