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的核心:

  • 支持集群没有单点故障
  • 支持集群扩展(高并发)
  • 在集群环境使用(大项目)

  1. 安装ES服务端(官方下载地址,依赖于JDK1.7以上,linux    修改配置文件Xms Xmx改为1G,运行bin/.bat包)图形界面和代码界面的端口不同9200和9300
  2. 了解Restfull风格,面向资源的架构风格。GET查询  PUT添加  POST修改  DELE删除  使用URL定位资源用HTTP描述进行操作。
  3. 选用一种图形界面客户端,简单操作
  4. 使用图形界面客户端执行各种命令
  5. 使用代码客户端来操作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查询语句:

过滤属于精确查找
查询属于模糊查找

性能区别:

  • 过滤结果可以缓存应用到后续请求
  • 查询语句同时匹配文档,计算相关性,所以更耗时,且不缓存
  • 过滤语句可有效地配合查询语句完成文档过滤

分词:

建立索引,查询等业务会使用分词。

  1. 集成分词器,在服务端通过插件集成分词器
  2. 设置字段的分词器,通过客户端告诉ES某个字段要使用哪个分词
IK插件源码下载
  1. mvn package install    将源码打包安装到本地库,放到ES的plugins文件夹
  2. plugin-descriptor.properties
  3. 分词器(可默认)词典配置:confiig/IKAnalyzer.cfg.xml
  4. 重启
  5. 测试分词器
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()//命中数