虽然全文搜索领域,Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。
但是,Lucene只是一个库。想要使用它,你必须使用Java来作为开发语言并将其直接集成到你的应用中,更糟糕的是,Lucene的配置及使用非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的。
① 使用复杂
② 不支持集群
① Es全文检索框架,使用比lusene简单
② Es支持集群,支持分布式
③ 支持json的操作
④ 一般大型全文检索都使用Es
⑤ 通过Restfull风格来操作Es(GET crm/user/1…)
① ES即为了解决原生Lucene使用的不足,优化Lucene的调用方式,并实现了高可用的分布式集群的搜索方案
② ES的索引库管理支持依然是基于Apache Lucene™的开源搜索引擎
③ ES也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的 RESTfulAPI来隐藏Lucene的复杂性,从而让全文搜索变得简单。
④ Es的核心不在于Lucene,其特点更多的体现为:
(1)分布式的实时文件存储,每个字段都被索引并可被搜索
(2)分布式的实时分析搜索引擎
(3)可以扩展到上百台服务器,处理PB级结构化或非结构化数据 1024KB-1MB
1.官方下载地址(https://www.elastic.co/downloads/elasticsearch)
2.运行es
3.验证es是否可以使用
访问:http://localhost:9200/ , 出现以下json数据表示es可以使用
透明性,暴露资源存在。
充分利用 HTTP 协议本身语义。
无状态,这点非常重要。在调用一个接口(访问、操作资源)的时候,可以不用考虑上下文,不用考虑当前状态,极大的降低了复杂度。
1.Kibana5.2.2下载地址:https://www.elastic.co/downloads/kibana
2.解压并编辑config/kibana.yml,设置elasticsearch.url的值为已启动的ES
3.启动Kibana5 :
先启动es,在启动Kibana5:bin\kibana.bat
4. 默认访问地址:http://localhost:5601
5.Es中的文档
ES是面向文档(document oriented)的,这意味着它可以存储整个对象或文档(document)。然而它不仅仅是存储,还会索引(index)每个文档的内容使之可以被搜索。在ES中,你可以对文档(而非成行成列的数据)进行索引、搜索、排序、过滤。
ES使用Javascript对象符号(JavaScript Object Notation),也就是JSON,作为文档序列化格式。JSON现在已经被大多语言所支持,而且已经成为NoSQL领域的标准格式。
6.文档的增删改
①创建索引文档
② 查询索引文档
③ 修改文档
1)更新所有文档 (旧文档先删除在新增新的文档)
2)局部更新(只更新一部分)
④ 删除文档
删除时的返回值中,found为true为表示想删除的值存在,false为不存在
⑤ 批量操作
③ 空搜索
没有指定任何的查询条件,只返回集群索引中的所有文档: GET _search
④ 分页搜索
和SQL使用 LIMIT 关键字返回只有一页的结果一样,Elasticsearch接受 from 和 size 参数:
size : 每页条数,默认 10 pageSize
from : 跳过开始的结果数,默认 0 beginIndex
Limit beginIndex,pageSize
beginIndex = (currentPage-1)*pageSize
如果你想每页显示5个结果,页码从1到3,那请求如下:
GET _search?size=5 --第1页
GET _search?size=5&from=5 --第2页
GET _search?size=5&from=10 --第3页
⑤ 查询字符串搜索
一个搜索可以用纯粹的uri来执行查询。在这种模式下使用搜索,并不是所有的选项都是暴露的。它可以方便快速进行 curl 测试。
查询年龄为25岁的员工
GET itsource/employee/_search?q=age:25
如果q后的参数不指定Fileds则默认查询_all字段(隐含的文档所有字段的连接内容)
类似的查询语法参考lucene,如:
+name:john +tweet:mary
+name:(mary john) +date:>2014-09-10
age[20 TO 30]
使用DSL查询,必须要传递query参数给ES。
普通搜索(匹配所有文档):
{
"query" : {
"match_all" : {}
}
}
如果需要使用过滤条件(在所有文档中过滤,红色部分默认可不写):
{
"query" : {
"bool" : {
"must" : [{
"match_all":{}
}],
"filter":{....}
}
}
}
match查询是一个标准查询,不管你需要全文本查询还是精确查询基本上都要用到它。
如果你使用match查询一个全文本字段,它会在真正查询之前用分析器先分析查询字符:
{
"query": {
"match": {
"fullName": "Steven King"
}
}
}
multi_match 查询允许你做 match查询的基础上同时搜索多个字段:(关键字搜索多个 不用)
{
"query":{
"multi_match": {
"query": "Steven King",
"fields": [ "fullName", "title" ]
}
}
}
{
"query": {
"bool": {
"must": {
"match_all": {}
},
"filter": {
"term": {
"tags": "elasticsearch"
}
}
}
}
}
Terms搜索与过滤
{
"query": {
"terms": {
"tags": ["jvm", "hadoop", "lucene"],
"minimum_match": 2
}
}
}
组合搜索bool可以组合多个查询条件为一个查询对象,查询条件包括must、should和must_not。
例如:查询爱好有美女,同时也有喜欢游戏或运动,且出生于1990-06-30及之后的人。
{
"query": {
"bool": {
"must": [{"term": {"hobby": "美女"}
}],
"should": [{"term": {"hobby": "游戏"}
},
{"term": {"hobby": "运动"}}
],
"must_not": [
{"range" :{"birth_date":{"lt": "1990-06-30"}}}
],
"filter": [...],
"minimum_should_match": 1
}
}
}
range过滤允许我们按照指定范围查找一批数据:
{
"query":{
"range": {
"age": {
"gte": 20,
"lt": 30
}
}
}
}
{
"query": {
"bool": {
"must": [{
"match_all": {}
}],
"filter": {
"exists": { "field": "gps" }
}
}
}
}
和term查询相似,前匹配搜索不是精确匹配,而是类似于SQL中的like ‘key%’
{
"query": {
"prefix": {
"fullName": "倪"
}
}
}
使用*代表0~N个,使用?代表1个。
{
"query": {
"wildcard": {
"fullName": "倪*华"
}
}
}
ES默认对英文文本的分词器支持较好,但和lucene一样,如果需要对中文进行全文检索,那么需要使用中文分词器,同lucene一样,在使用中文全文检索前,需要集成IK分词器。
1.ES的IK分词器插件源码地址:https://github.com/medcl/elasticsearch-analysis-ik
2.解压target/releases/elasticsearch-analysis-ik-5.2.2.zip文件
3.并将其内容放置于ES根目录/plugins/ik
4.重启ES服务器
5. 测试分词器
注意:IK分词器有两种类型,分别是ik_smart分词器和ik_max_word分词器。
ik_smart: 会做最粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”。
ik_max_word: 会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,会穷尽各种可能的组合;
ES的文档映射(mapping)机制用于进行字段类型确认,将每个字段匹配为一种确定的数据类型。(相当于写表结构)
①基本字段类型
字符串:text(分词),keyword(不分词) StringField(不分词文本),TextFiled(要分词文本) text默认为全文文本,keyword默认为非全文文本
数字:long,integer,short,double,float
日期:date
逻辑:boolean
② 复杂数据类型
对象类型:object
数组类型:array
地理位置:geo_point,geo_shape
查看索引类型的映射配置:GET shop/goods/_mapping
ES在没有配置Mapping的情况下新增文档,ES会尝试对字段类型进行猜测,并动态生成字段和类型的映射关系。
{
“id” : 1,
“girl” : {
“name” : “王小花”,
“age” : 22
}
}
对应的mapping配置:
{
"properties": {
"id": {"type": "long"},
"girl": {
"properties":{
"name": {"type": "keyword"},
"age": {"type": "integer"}
}
}
}
}
注意:Lucene不理解内置对象,一个lucene文档包含键值对的一个扁平化列表,以便于ES索引内置对象,它会把上面格式文档转换为类似这样:
{
“id”: 1,
“girl.name”:“王小花”,
“girl.age”:26
}
注意:数组中元素的类型必须一致。
{
“id” : 1,
“hobby” : [“王小花”,“林志玲”]
}
对应的mapping配置是:
{
“properties”: {
“id”: {“type”: “long”},
“hobby”: {“type”: “keyword”}
}
}
{
"id" : 1,
"girl":[{"name":"林志玲","age":32},{"name":"赵丽颖","age":22}]
}
对应的映射配置为:
"properties": {
"id": {
"type": "long"
},
"girl": {
"properties": {
"age": { "type": "long" },
"name": { "type": "text" }
}
}
}
注意:同内联对象一样,对象数组也会被扁平化索引
{
"user.girl.age": [32, 22],
"user.girl.name": ["林志玲", "赵丽颖"]
}
动态模板实现
在实际应用场景中,一个对象的属性中,需要 全文检索的字段较少,大部分字符串不需要分词,因此,需要利用全局模板覆盖自带的默认模板:
PUT _template/global_template //创建名为global_template的模板
{
"template":"*", //匹配所有索引库
"settings":{"number_of_shards":1},//匹配到的索引库只创建1个主分片
"mappings":{
"_default_":{
"_all":{
"enabled":false //关闭所有类型的_all字段
},
"dynamic_templates":[
{
"string_as_text":{
"match_mapping_type":"string",//匹配类型string
"match":"*_text", //匹配字段名字以_text结尾
"mapping":{
"type":"text",//将类型为string的字段映射为text类型
"analyzer":"ik_max_word",
"search_analyzer":"ik_max_word",
"fields":{
"raw":{
"type":"keyword",
"ignore_above":256
}
}
}
}
},
{
"string_as_keyword":{
"match_mapping_type":"string",//匹配类型string
"mapping":{
"type":"keyword"//将类型为string的字段映射为keyword类型
}
}
}
]
}
}
}