认识ElasticSerach

虽然全文搜索领域,Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。
但是,Lucene只是一个库。想要使用它,你必须使用Java来作为开发语言并将其直接集成到你的应用中,更糟糕的是,Lucene的配置及使用非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的。

1.Lucene的缺点

① 使用复杂
② 不支持集群

2. ElasticSerach的特点

① Es全文检索框架,使用比lusene简单
② Es支持集群,支持分布式
③ 支持json的操作
④ 一般大型全文检索都使用Es
⑤ 通过Restfull风格来操作Es(GET crm/user/1…)

3. ElasticSerach简介

① ES即为了解决原生Lucene使用的不足,优化Lucene的调用方式,并实现了高可用的分布式集群的搜索方案
② ES的索引库管理支持依然是基于Apache Lucene™的开源搜索引擎
③ ES也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的 RESTfulAPI来隐藏Lucene的复杂性,从而让全文搜索变得简单。
④ Es的核心不在于Lucene,其特点更多的体现为:
(1)分布式的实时文件存储,每个字段都被索引并可被搜索
(2)分布式的实时分析搜索引擎
(3)可以扩展到上百台服务器,处理PB级结构化或非结构化数据 1024KB-1MB

安装ES

1.官方下载地址(https://www.elastic.co/downloads/elasticsearch)

es 分词检索忽略大小写_分词器

2.运行es

es 分词检索忽略大小写_字段_02


3.验证es是否可以使用

访问:http://localhost:9200/ , 出现以下json数据表示es可以使用

es 分词检索忽略大小写_搜索_03

ES的交互

1.Restful的认识

Restful具有的好处:

透明性,暴露资源存在。
充分利用 HTTP 协议本身语义。
无状态,这点非常重要。在调用一个接口(访问、操作资源)的时候,可以不用考虑上下文,不用考虑当前状态,极大的降低了复杂度。

特征
  1. Server提供的RESTful API中,URL中只使用名词来指定资源。
    “资源”是REST架构或者说整个网络处理的核心。比如:
    GET http://api.itsource.cn/emp/323: 获取323号员工的基本资料;
    GET http://api.itsource.cn/emps: 获取源码时代所有员工资料列表;
  2. REST 是面向资源的,这个概念非常重要,而资源是通过 URI 进行暴露
    URI 的设计只要负责把资源通过合理方式暴露出来就可以了。对资源的操作与它无关,所以REST 通过 URI 暴露资源时,会强调不要在 URI 中出现动词。
    比如:左边是错误的设计,而右边是正确的
    GET /rest/api/getDogs -> GET /rest/api/dogs 获取所有小狗狗
    GET /rest/api/addDogs -> POST /rest/api/dogs 添加一个小狗狗
    POST /rest/api/editDogs/12 -> PUT /rest/api/dogs/12 修改一个小狗狗
    POST /rest/api/deleteDogs/12 -> DELETE /rest/api/dogs/12 删除一个小狗狗
    左边的这种设计,很明显不符合REST风格,URI 只负责准确无误的暴露资源,而 getDogs/addDogs…已经包含了对资源的操作,这是不对的。相反右边却满足了,它的操作是使用标准的HTTP动词来体现。
  3. 用HTTP协议里的动词来实现资源的添加,修改,删除等操作。
    即通过HTTP动词来实现资源的状态扭转:
    GET 用来获取资源,
    POST 用来新建资源(也可以用于更新资源),
    PUT 用来更新资源,
    DELETE 用来删除资源。
    比如:
    GET http://api.itsource.cn/emp/323 获取一个员工
    POST http://api.itsource.cn/emp/232: 添加或修改一个员工
    PUT http://api.itsource.cn/emp: 修改员工资料
    DELETE http://api.itsource.cn/emp/323: 删除323号员工

Es辅助管理工具Kibana5

1.Kibana5.2.2下载地址:https://www.elastic.co/downloads/kibana 2.解压并编辑config/kibana.yml,设置elasticsearch.url的值为已启动的ES

es 分词检索忽略大小写_字段_04


3.启动Kibana5 :

先启动es,在启动Kibana5:bin\kibana.bat

es 分词检索忽略大小写_ElasticSearch_05


es 分词检索忽略大小写_ElasticSearch_06

4. 默认访问地址:http://localhost:5601

es 分词检索忽略大小写_es 分词检索忽略大小写_07

5.Es中的文档

ES是面向文档(document oriented)的,这意味着它可以存储整个对象或文档(document)。然而它不仅仅是存储,还会索引(index)每个文档的内容使之可以被搜索。在ES中,你可以对文档(而非成行成列的数据)进行索引、搜索、排序、过滤。

ES使用Javascript对象符号(JavaScript Object Notation),也就是JSON,作为文档序列化格式。JSON现在已经被大多语言所支持,而且已经成为NoSQL领域的标准格式。

es 分词检索忽略大小写_分词器_08


6.文档的增删改

①创建索引文档

es 分词检索忽略大小写_ElasticSearch_09

es 分词检索忽略大小写_es 分词检索忽略大小写_10


② 查询索引文档

es 分词检索忽略大小写_分词器_11


③ 修改文档

1)更新所有文档 (旧文档先删除在新增新的文档)

es 分词检索忽略大小写_es 分词检索忽略大小写_12


2)局部更新(只更新一部分)

es 分词检索忽略大小写_ElasticSearch_13


④ 删除文档

es 分词检索忽略大小写_字段_14


删除时的返回值中,found为true为表示想删除的值存在,false为不存在

es 分词检索忽略大小写_es 分词检索忽略大小写_15


⑤ 批量操作

es 分词检索忽略大小写_字段_16

7.文档的简单查询

① 通过文档id获取

② 批量获取

es 分词检索忽略大小写_es 分词检索忽略大小写_17

es 分词检索忽略大小写_es 分词检索忽略大小写_18

③ 空搜索

没有指定任何的查询条件,只返回集群索引中的所有文档: 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查询与过滤

使用DSL查询,必须要传递query参数给ES。

match_all:全匹配

普通搜索(匹配所有文档):

{
	"query" : {
	 "match_all" : {}
	}
}

如果需要使用过滤条件(在所有文档中过滤,红色部分默认可不写):

{
	"query" : {
		"bool" : {
		 "must" : [{
			  "match_all":{}
		 }],
		"filter":{....}
	 	  }
	  }
}

标准查询(match和multi_match)

match查询是一个标准查询,不管你需要全文本查询还是精确查询基本上都要用到它。
如果你使用match查询一个全文本字段,它会在真正查询之前用分析器先分析查询字符:

{
        	"query": {
        		"match": {
      			  "fullName": "Steven King"
       			 }
    		 }
    }

multi_match 查询允许你做 match查询的基础上同时搜索多个字段:(关键字搜索多个 不用)

{
  	  "query":{
    		"multi_match": {
   				 "query": "Steven King",
    		   	"fields": [ "fullName", "title" ]
 			   }
 	   }
    }

单词搜索与过滤(Term和Terms) 类似 where tags=’ elasticsearch’

{
   	 "query": {
  		  "bool": {
  			  "must": { 
   				 "match_all": {} 
  			  }, 
  			  "filter": { 
  				  "term": { 
   					 "tags": "elasticsearch"
				    } 
			    } 
   			 } 
	    }
    }

Terms搜索与过滤

{
    	"query": {
  			  "terms": {
   					 "tags": ["jvm", "hadoop", "lucene"],
  					  "minimum_match": 2
  			  }
  		  }
    }

组合条件搜索与过滤(Bool)

组合搜索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)

range过滤允许我们按照指定范围查找一批数据:

{
	"query":{
		"range": {
			 "age": {
				 "gte": 20,
   				 "lt": 30
			  }
		}
	}
}

存在和缺失过滤器(exists和missing) 一般用在 判断这个人是否存在

{
	"query": {
	  	"bool": {
			"must": [{
				"match_all": {}
			}],
			"filter": {
				"exists": { "field": "gps" }
			}
		}
	}
}

前匹配搜索与过滤(prefix)

和term查询相似,前匹配搜索不是精确匹配,而是类似于SQL中的like ‘key%’

{
	"query": {
  		  "prefix": {
   				 "fullName": "倪"
  		  }
	}
}

通配符搜索(wildcard)

使用*代表0~N个,使用?代表1个。

{
   		 "query": {
    		"wildcard": {
   				 "fullName": "倪*华"
    		}
   		 }
    }

案例

es 分词检索忽略大小写_搜索_19

分词与映射

ik分词器

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. 测试分词器

es 分词检索忽略大小写_搜索_20

注意:IK分词器有两种类型,分别是ik_smart分词器和ik_max_word分词器。
ik_smart: 会做最粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”。
ik_max_word: 会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,会穷尽各种可能的组合;

文档映射Mapper

ES的文档映射(mapping)机制用于进行字段类型确认,将每个字段匹配为一种确定的数据类型。(相当于写表结构)

1.Es字段类型

①基本字段类型
字符串:text(分词),keyword(不分词) StringField(不分词文本),TextFiled(要分词文本) text默认为全文文本,keyword默认为非全文文本
数字:long,integer,short,double,float
日期:date
逻辑:boolean
② 复杂数据类型
对象类型:object
数组类型:array
地理位置:geo_point,geo_shape

2.默认映射

查看索引类型的映射配置:GET shop/goods/_mapping
 ES在没有配置Mapping的情况下新增文档,ES会尝试对字段类型进行猜测,并动态生成字段和类型的映射关系。

3.简单类型映射

修改映射类型

es 分词检索忽略大小写_ElasticSearch_21

对象映射

{
  	  “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类型
					    				}
 						   }
  				  }
		    ]
 	   }
    }
}