002_分布式搜索引擎Elasticsearch的查询与过滤

本文详细介绍Elasticsearch的基本操作,包括写入、删除、查询、更新和搜索等,并演示了如何利用DSL进行复杂查询,最后展示了中文分词的具体实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、写入

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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,通过下面的命令可以删除这条记录:

1
2
3
4
5
6
7
8
9
10
11
12
13
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)出来

1
2
3
4
5
6
7
8
9
10
11
12
13
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格式是否更阅读友好

1
2
3
4
5
6
7
8
9
10
11
12
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

1
2
3
4
5
6
7
8
9
10
11
12
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中(并不会覆盖老的记录)。

首先创建一条记录

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

将counter的值加4

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

也可以添加一个tag的值

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

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

1
2
3
4
5
6
7
8
9
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中,例如:

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

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

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

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

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

1
2
3
4
5
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,例如下面这个例子

1
2
3
4
5
6
7
8
9
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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之类的 一直维护一个连接

 

更多限制条件的搜素

1
2
3
4
5
6
7
8
9
curl -XGET  'localhost:9200/test/_search?pretty'  -d'{
     "from" : 0,
     "size" : 1,
     "_source" : [ "title" "allnum" ],
     "query" : {
         "match" : {  "title" "地铁跑酷"  }
     },
    "sort" : {  "allnum" : {  "order" "desc"  }}
}'
2、使用should
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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、过滤器
1
2
3
4
5
6
7
8
9
10
curl -XPOST  'localhost:9200/test/_search?pretty'  -d'{
     "query" : {
         "filtered" : {
             "query" : {
                  "match_all" : {}
               },
              "filter" : {
                  "range" : {  "allumn" : {  "gte" : 20000,  "lte" : 30000 } } } }
                }
}'
5、聚合
1
2
3
4
5
6
7
curl  -XPOST   'localhost:9200/test/_search?pretty'  -d'{
     "size" : 0,
     "aggs" : {
         "group_by_state" : {
             "terms" : {  "field" "state"  } }
          }
}'
6、terms 过滤
1
2
3
4
5
6
7
8
9
10
curl  -XPOST   'localhost:9200/test/_search?pretty'  -d'{
   "query" : {
     "terms" : {
       "status" : [
         304,
         302
       ]
     }
   }
}
7、range 过滤
1
2
3
4
5
6
7
8
9
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条件

1
2
3
4
5
{
     "exists" :   {
         "field" :     "title"
     }
}
9、bool 过滤

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

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

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

1
2
3
4
5
6
7
8
9
10
{
     "bool" : {
         "must" :     {  "term" : {  "folder" "inbox"  }},
         "must_not" : {  "term" : {  "tag" :     "spam"   }},
         "should" : [
                     "term" : {  "starred" true    }},
                     "term" : {  "unread" :   true    }}
         ]
     }
}

七、中文分词

创建索引
1
curl -XPUT http: //localhost :9200 /index
创建映射
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
             }
         }
     }
}'
为索引添加一些内容
1
2
3
4
5
6
7
8
9
10
11
12
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" : "中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首" }
'
进行查询
1
2
3
4
5
6
7
8
9
10
11
12
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.cnblogs.com/chenpingzhao/p/6067350.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值