Lucene只是一个库,需要使用Java语言继承到应用中,配置和使用非常复杂。
缺点:
- 只能在Java项目中使用
- 使用非常复杂--创建索引和搜索索引代码多
- 不支持集群环境-索引数据不同步(不支持大型项目)
- 索引的数据太多的话,和应用共用磁盘空间会减少。
Luncene直接通过java API调用,而ES封装了简单的RESTful请求。
Elasticsearch是一个基于Apache Lucene的开源搜索引擎,通过简易的API来隐藏Lucene的复杂性。ES的基本结构包括,Cluster集群(由n个节点组成),Node实例节点,Index索引(一系列documents的集合),Shard分片(索引的数据是分配到各个分片的),Replica备份节点(相应有Primay Shard主分片)
ES和RDMS的区别:
二、ES不是什么
1、ES不是数据库,不是可靠的数据存储系统。
[Indexing] A network partition can cause in flight documents to be lost
2、ES不是实时系统,数据写入成功只是translog成功,类似mysql的binlog,同理删除数据也不是实时的。其实ES内部有一个后台线程,定时将内存的数据写入到存储引擎中。当然可以写入数据后refresh,但是会重新打开所有索引文件,需要解压和刷缓存等等,性能影响极大
3、ES不是一个强一致性的系统。也就是说同样的query多次查询的数据可能会不一致。由于shard的主分片和副本是由独立的节点去刷新的,刷新的频率并不同步,这样同样的query发送到不同的分片(主片和从片)上看到的数据是不同的,导致的结果是查询到的数据也不完全同步。简单说,ES是一个最终一致性系统
ES的核心:
- 支持集群没有单点故障
- 支持集群扩展(高并发)
- 在集群环境使用(大项目)
- 安装ES服务端(官方下载地址,依赖于JDK1.7以上,linux 修改配置文件Xms Xmx改为1G,运行bin/.bat包)图形界面和代码界面的端口不同9200和9300
- 了解Restfull风格,面向资源的架构风格。GET查询 PUT添加 POST修改 DELE删除 使用URL定位资源用HTTP描述进行操作。
- 选用一种图形界面客户端,简单操作
- 使用图形界面客户端执行各种命令
- 使用代码客户端来操作ES的服务端
图形界面客户端 端口9200
- Curl命令方式(window不支持)
- 火狐的插件 POSTER
- 辅助管理工具Kibana(官方推荐,注意版本一致)
Kibana下载,并修改配置config/kibana.yml设置elasticsearch.url值为已启动的ES ,启动bin\kibana.bat,默认访问地址http://localhost:5601
ES是面向文档的,它可以存储整个对象或文档,ES使用JSON作为文档序列化格式。
元数据:
- _index:文档存储位置
- _type:文档的类型
- _id:文档标识
- _source:文档原始数据
- _all:所有字段值拼接
文档的增删改
#添加文档
PUT test/employee/1{ 若没有指定id,自动生成
"id":1,
"name":"jordan",
"age":23,
"info":{
"address":"chengdu",
"email":"jk@12.com"
}
}
#获取一个文档
GET test/employee/1
#修改
PUT 先删除,后添加
POST test/employee/1/_update{ -------------局部更新,原有的保持不变
"doc":{
}
}
#删除
DELETE test/employee/2
#获取所有
GET test/employee/_search
#批量查询
GET test/employee/_mget
{
"ids":["1","2"]
}
#高级查询:排序+分页+截取字段
GET test/employee/_search?q=age:38 q参数表示查询字符串
[30 TO 60]&sort=age:desc&from=0&size=2&_source=name,age
查询条件比较多,更复杂的情况下使用DSL查询与过滤。
以json请求体的形式
普通查询:GET itsource/employee/_search?q=fullname:jordan
DSL模式:GET itsource/employee/_search{
"query":{
"match":{
"fullname":"jordan"
},
"sort":{
"age":{
"order":"desc"
}
},
"from":0,
"size":2,
"_source":["name","age"]
}
}
DSL过滤和DSL查询语句:
过滤属于精确查找
查询属于模糊查找
性能区别:
- 过滤结果可以缓存应用到后续请求
- 查询语句同时匹配文档,计算相关性,所以更耗时,且不缓存
- 过滤语句可有效地配合查询语句完成文档过滤
分词:
建立索引,查询等业务会使用分词。
- 集成分词器,在服务端通过插件集成分词器
- 设置字段的分词器,通过客户端告诉ES某个字段要使用哪个分词
IK插件源码下载
- mvn package install 将源码打包安装到本地库,放到ES的plugins文件夹
- plugin-descriptor.properties
- 分词器(可默认)词典配置:confiig/IKAnalyzer.cfg.xml
- 重启
- 测试分词器
POST _analyze
{
"analyzer":"ik_smart", ik_smart粗粒度拆分 默认是细粒度ik_max_word
"text":"软件架构工程师 很幸苦的职业"
}
文档映射Mapper
用于进行字段类型确认(字段是什么类型,哪个分词器),将每个字段匹配一种确定的数据类型。
ES支持的类型:
- 字符串 基本字段类型String :text分词 keyword不分词
- 数字 :long integer short double float
- 日期:date
- 逻辑 :boolean
- 对象:object
- 数组:array
- 地理位置:geo_point geo_shape
查看索引类型配置映射:GET test/_mapping/employee 添加文档时虽然没有指定,但有默认映射关系。
全局映射:
- 默认方式 _default_
- 模板映射
- 自定义映射
Java API
ES为Java用户提供了两种内置客户端,通过客户端就能通过CRUD+DSL操作
- 节点客户端:以无数据身份加入集群,它自己不存储任何数据,但是知道数据在集群中的具***置,并且能够直接转发请求到对应的节点上。
- 传输客户端:发送请求到远程集群,自己不加入集群,只是简单转发请求给集群中的节点。
创建传输客户端:
//创建传输客户端 Settings settings=Settings.builder().put("client.transport.sniff",true); TransportClient client=new PreBuiltTransportClient(settings); //给出主机线索 TransportAddress transportAddress=new InetSocketTransportAddress(InetAddress.getByNme("127.0.0.1"),9300); client.addTransportAddress(transportAddress); System.out.println(client); client.close();
添加:
//获取客户端 TransportClinet client=getClient(); //执行操作 IndexRequestBuilder builder=client.prepareIndex(INDEX,TYPE,"1"); //准备执行对象所需数据 Map<String,Object> employeeMap=new HashMap<>(); employeeMap.put("id",1L); employeeMap.put("name","el"); employeeMap.put("age",18); //将数据添加给执行对象 builder.setSource(employeeMap); IndexResponse response=builder.get(); //关闭客户端 client.close();
获取:
GetRequestBuilder builder=client.prepareGet(INDEX,TYPE,"1"); GetReponse response=builder.get(); System.out.println(response.getSource());
修改:
client.prepareUpdate(INDEX,TYPE,"1");
Map内容进行setDoc().get();
删除:
client.prepareDelete(INDEX,TYPE,"1");
DSL=query+fileter:
SearchRequestBuilder builder=client.prepareSearch(INDEX);
builder.setTypes(TYPE);设置类型
builder.setQuery();//设置查询条件
builder.setSort("age",SortOrder.DESC);
builder.setFrom(0).etSize(10);//分页
SearchReponse reponse=builder.get();
SearchHits hits=reponse.getHits(); 返回结果封装,总命中数+命中集合
hits.getTotalHits()//命中数