• 分布式搜索引擎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

  • 相关阅读:
    从一道比较奇葩的笔试题说起
    如何用一个语句判断一个整数是不是二的整数次幂——从一道简单的面试题浅谈C语言的类型提升(type promotion)
    C指针(转)
    raspberry-常用命令
    raspberry-同路由器用putty和vnc桌面登录方法
    结对编程-黄金点游戏
    软件工程第一次作业
    Python机器学习(9)——聚类算法之K均值
    Python机器学习(8)——推荐算法之推荐矩阵
    Python机器学习(7)——SVM支持向量机
  • 原文地址:https://www.cnblogs.com/chenpingzhao/p/6067350.html
Copyright © 2020-2023  润新知