Elasticsearch介绍
ElasticSerach定义:
ES=elasticsearch简写,
Elasticsearch是一个开源的高扩展的分布式全文检索引擎,
它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据。
Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,
但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,
从而让全文搜索变得简单。
ES和Lucene区别:
1、Lucene只是一个库。想要使用它,你必须使用Java来作为开发语言并将其直接集成到你的应用中,
更糟糕的是,Lucene非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的。
2、Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,
但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。
ES和Solr区别
1、es基本是开箱即用,非常简单。
2、Solr 利用 Zookeeper 进行分布式管理,而 Elasticsearch 自身带有分布式协调管理功能。
3、Solr 支持更多格式的数据,比如JSON、XML、CSV,而 Elasticsearch 仅支持json文件格式。
4、Solr 官方提供的功能更多,而 Elasticsearch 本身更注重于核心功能,高级功能多有第三方插件提供,例如图形化界面需要kibana友好支撑
5、Solr 查询快,但更新索引时慢(即插入删除慢),用于电商等查询多的应用;ES建立索引快(即查询慢),即实时性查询快,用于facebook新浪等搜索。Solr 是传统搜索应用的有力解决方案,但 Elasticsearch 更适用于新兴的实时搜索应用。
6、Solr比较成熟,有一个更大,更成熟的用户、开发和贡献者社区,而 Elasticsearch相对开发维护者较少,更新太快,学习使用成本较高。
启动elasticsearch
运行es,从elatic官网下载elasticsearch
直接解压到某个目录下,注意不要有中文路径
启动es 进入bin目录执行elasticsearch.bat
在浏览器输入localhost:9200 访问出现以下信息启动成功
{
name: "node-1",
cluster_name: "my-application",
cluster_uuid: "_na_",
version: {
number: "6.5.4",
build_flavor: "default",
build_type: "zip",
build_hash: "d2ef93d",
build_date: "2018-12-17T21:17:40.758843Z",
build_snapshot: false,
lucene_version: "7.5.0",
minimum_wire_compatibility_version: "5.6.0",
minimum_index_compatibility_version: "5.0.0"
},
tagline: "You Know, for Search"
}
ES数据架构和Mysql对比
Index ---- DataBase
Type ----- Table
Document— Row
ES集群颜色
绿色:健康,主分片和副分片都可用
黄色:警告,主分片可用,没有副本分片
红色:错误,主分片中部分索引已经不可使用,但是不影响其他分片正常使用
RESTfull 风格
POST : 添加
GET : 查询
PUT : 修改 (没有此数据则添加数据,如果有则修改数据)
DELETE: 删除
安装head插件:[https://www.cnblogs.com/hts-technology/p/8477258.html](https://www.cnblogs.com/hts-technology/p/8477258.html)
运行head插件 在D:\ELK\elasticsearch-6.5.4\elasticsearch-head-master下cmd 运行 grunt server
如下信息代表启动成功:访问http:localhost:9100
Running "connect:server" (connect) task
Waiting forever...
Started connect web server on http://localhost:9100
_index: 索引名称
_type: 类型名称
_id:数据的唯一id,id为自动生成
_score: 分数,命中分数
文档索引的创建
http://localhost:9200/book-002/jk-book/1/
请求方法为 : POST
{
“_index”: “book-002”, 索引名称
“_type”: “jk-book”, 类型名称
“_id”: “1”, 唯一ID,如果指定了ID则使用指定的,没有指定ID则ES会自动补充ID
“_version”: 1, 数据版本号,新创建的数据从1开始,每次对数据修改则加1
“result”: “created”, created:创建成功,updated:修改成功
“_shards”: {
“total”: 2,
“successful”: 1,
“failed”: 0
},
“_seq_no”: 0,
“_primary_term”: 1
}
head插件简单操作:https://blog.csdn.net/weixin_41986096/article/details/86737967
启动Kibana 在/bin/kibana.bat
访问:http://localhost:5601
启动Kibana后会在ES中创建一个名为.Kibana所以只有一个分片
kibana操作语法和命令
GET _cat/health 查看当前索引状态
GET _cat/indices 查看所有集群状态
GET _search 查询所有内容
{
"query": {
"match_all": {
}
}
}
{
“_index” : “item_index”, 索引
“_type” : “item_type”, 类型
“_id” : “2”, 索引Id
“_score” : 1.0, 分数
“_source” : { 数据
“id” : 2, 实体类对象的属性 id要和_id一致
“title” : “坚果手机R1”,
“category” : " 手机",
“brand” : “锤子”,
“price” : 3699.0,
“images” : “http://image.baidu.com/13123.jpg”
}
}
查询指定索引和类型
GET /book-002/jk-book/_search
{
"query": {
"match_all": {
}
}
}
添加数据
POST /book-002/jk-book/3
{
"id":3,
"name":"springCluod",
"author":"王听话",
"price":250,
"createTime":"2019-01-22"
}
修改数据
PUT /book-002/jk-book/3
{
"id":3,
"name":"springCluod",
"author":"王不听话",
"price":250,
"createTime":"2019-01-22"
}
删除数据
DELETE /book-002/jk-book/4
GET /book-002/jk-book/_search
{
"query": {
"match": {
"name": "ES6" 条查
}
},
"highlight": {
"fields": {
"name": {} 指定字段高亮 内容
}
}
}
页面设置高亮
em {
font-style: normal;
color: #c00;
}
a em {
text-decoration: underline;
}
em {
font-style: normal;
color: #c00;
}
区间查询 结合 bool使用
GET /book-002/jk-book/_search
{
"query": {
"bool": {
"must": [
{
"match_all": {}
}
],
"filter": {
"range": {
"price": {
"gte": 201, 大于等于
"lte": 300 小于等于
}
}
}
}
}
}
短语搜索 (查询为一个词语搜索,不会拆分进行搜)
GET /book-002/jk-book/_search
{
"query": {
"match_phrase": {
"name": "大数据"
}
}
}
sort 排序 from起始条数 size每页条数
GET /book-002/jk-book/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"price": { 排序字段
"order": "asc"
}
}
],
"from": 2,
"size": 2
}
ES配置ik分词器
ik分词器官方已经提供好词汇
将ik分词器的配置信息放入 在es目录/plugins/ik/ 目录下
注意ik目录需要手动创建
中国人民大会堂
ik_smart: 简单分词器方式,只能组成一次词汇进行分词 中国 人民大会堂
ik_max_word: 深度分词器方式,将所有能组成的词汇进行分词
standard:标准分词器 中 国 人 民
GET /_analyze?pretty
{
"analyzer": "ik_smart",
"text": "我爱中国人民大会堂"
}
深度分词器 我爱 中国 中国人 人民 大会堂 人民大会堂 中国人民
PUT /ik-index/
DELETE /ik-index/
POST /ik-index/ik-type/_mapping
{
"properties": {
"content":{
"type": "text",
"analyzer": "ik_max_word",
"store": true
}
}
}
POST /ik-index/ik-type/_bulk
{"index":{"_id":1}}
{"content":"我爱电影"}
{"index":{"_id":2}}
{"content":"我爱你电影"}
{"index":{"_id":3}}
{"content":"我爱看电影"}
自定义词汇
在ik目录/config下创建自定义词汇文件:文件名.dic
在文件中添加词汇格式为:每行为一个词汇
注意:更新后自定义词汇只会对之后的数据起作用
在D:\ELK\elasticsearch-6.5.4\plugins\ik\config下
配置扩展词汇IKAnalyzer.cfg.xml配置自定义文件(my_word.dic)
my_word.dic
改完重启生效
同义词:
1.创建文件:在es目录/config/analysis/synonym.txt
2.文件内容同义词汇为一行每个词汇用逗号分隔
3.创建索引的时候指定同义词汇文件
PUT /index-ik-006/
{
"settings": {
"number_of_shards": 5, #指定分片数量
"number_of_replicas": 1, #指定副本数量
"analysis": { #自定义分词方式
"analyzer": { #创建自自定义分词方式
"ik_synonym": { #指定分词方式名称,会在映射属性的时候用到
"type": "custom",
"tokenizer": "ik_max_word", #指定同义词类型为ik_max_word
"filter": [
"my_synonym_filter" #找到同义词过滤器
]
}
},
"filter": { #配置分词过滤器
"my_synonym_filter": {
"type": "synonym", #指定类型为同义词
"synonyms_path": "analysis/synonym.txt" #指定同义词配置文件
}
}
}
}
}
4.对属性添加映射
#添加属性映射以及指定那个属性进行分词
POST /index-ik-006/test-ik/_mapping
{
"properties": {
"content":{
"type": "text",
"analyzer": "ik_synonym", #分词方式为自定义同义词方式,创建索引的时候有定义
"store": true
},
"price":{
"type": "double"
}
}
}
5. 添加数据,搜索数据
#给索引添加数据
POST /index-ik-006/test-ik/100
{
"content":"御帝哥哥",
"price":100
}
GET /index-ik-006/test-ik/_search
{
"query": {
"match": {
"content": "玄奘"
}
},
"highlight": {
"fields": {
"content": {}
}
}
}
同义词–》分词:
西红柿-> 番茄,洋柿子,圣女果
土豆->马铃薯,tudou,tu豆
红薯->地瓜,番薯
5年---》五年
gaokao--》高考
3nian ---》 三年
mo拟--》模拟
springboot整合es
在yml文件中配置
spring:
data:
elasticsearch:
repositories:
enabled: true
cluster-name: my-application
cluster-nodes: localhost:9300
// 第一种是 spring data封装的 ElasticsearchRepository
@Autowired
private UserDao userDao;
// 第二种是 spring 封装 ElasticsearchTemplate
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@GetMapping("/selectUsers/{q}")
public List selectUsers(@PathVariable String q){
List userList = new ArrayList();
// 获取ES操作的客户端
Client client = elasticsearchTemplate.getClient();
// 定义查询对象,指定索引名称和类型名称,也可以定义query查询
SearchRequestBuilder searchRequestBuilder = client
.prepareSearch("user-004")
.setTypes("user-t")
.setQuery(QueryBuilders.matchQuery("userName", q));
// 获取高亮对象
HighlightBuilder highlightBuilder = new HighlightBuilder();
// 设置高亮字段
highlightBuilder.field("userName");
// 将高亮对象放入查询对象中
searchRequestBuilder.highlighter(highlightBuilder);
// 获取查询返回的对象
SearchResponse searchResponse = searchRequestBuilder.get();
// 通过SearchResponse对象获取命中的结果集
SearchHits hits = searchResponse.getHits();
// 命中的结果集获取iterator迭代器
Iterator iterator = hits.iterator();
while (iterator.hasNext()){
User user = new User();
SearchHit searchHit = iterator.next();
Map highlightMap = searchHit.getHighlightFields();
HighlightField userName = highlightMap.get("userName");
Map sourceAsMap = searchHit.getSourceAsMap();
user.setUserId(sourceAsMap.get("userId").toString());
user.setUserName(userName.getFragments()[0].toString());
userList.add(user);
}
return userList;
}
@RequestMapping("/save")
public String insertUser(){
User user = new User();
user.setUserId(UUID.randomUUID().toString());
user.setUserName("小田");
userDao.save(user);
return "insert success";
}
@RequestMapping("/selectList")
public List selectUserList(){
List userList = new ArrayList();
Iterable iterable = userDao.findAll();
Iterator iterator = iterable.iterator();
while (iterator.hasNext()){
User user = iterator.next();
userList.add(user);
}
return userList;
}
@GetMapping("/selectById/{id}")
public User selectById(@PathVariable String id){
User user = userDao.findById(id).get();
return user;
}
@RequestMapping("/update")
public String updateUser(){
User user = new User();
user.setUserId("d9894c6d-57ce-4ded-a601-1f62eba5674d");
user.setUserName("小田");
userDao.save(user);
return "update success";
}
@RequestMapping("/delete/{id}")
public String deleteUser(@PathVariable String id){
userDao.deleteById(id);
return "delete success";
}
项目整合案例
1、创建项目是导入默认web和es的jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
2、在application中配置
#配置集群名称
spring.data.elasticsearch.cluster-name=elasticsearch
#配置集群节点 9300 集群通信端口
spring.data.elasticsearch.cluster-nodes=localhost:9300
3、创建实体类,类上加
@Document(indexName = "product",type = "estype",replicas = 2,createIndex = false)
实体类属性定义
@Id
//映射es的字段
@Field(store = true)
private Integer productId;
/**
* searchAnalyzer 查询时使用的分词器
* analyzer 是创建倒排索引时使用的分词器
*/
@Field(type=FieldType.Text,store = true,searchAnalyzer="ik_max_word",analyzer="ik_max_word")
private String productName;
@Field(type=FieldType.Text,store = true,searchAnalyzer="ik_max_word",analyzer="ik_max_word")
private String productDesc;
4、创建controller类
类上加
@controller
类中注入
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Autowired
private ProductRepository productDao;
方法示例:
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Autowired
private ProductRepository productDao;
@GetMapping("addProduct")
public void addProduct(){
Product product = new Product();
product.setProductId(2);
product.setProductName("苹果手机");
product.setProductDesc(" 香槟金 128G存储");
productDao.save(product);
}
@GetMapping("queryProduct")
public Product queryProduct(){
Product product = productDao.findByProductName("苹果手机");
return product;
}
@GetMapping("queryPrductList")
public List<Product> queryPrductList(){
//获取elasticsearch连接
Client client = elasticsearchTemplate.getClient();
//创建一个es的查询构造器
SearchRequestBuilder searchRequestBuilder = client.prepareSearch("product").setTypes("estype");
searchRequestBuilder.setQuery(QueryBuilders.matchQuery("productName","手机"));
//设置高亮显示
HighlightBuilder highlightBuilder = new HighlightBuilder();
//设置需要高亮显示的字段
highlightBuilder.field("productName");
//设置高亮显示的开始标签
highlightBuilder.preTags("");
//设置高亮显示结束标签
highlightBuilder.postTags("");
//把高亮对象嵌入到查询器中
searchRequestBuilder.highlighter(highlightBuilder);
searchRequestBuilder.addSort("productId", SortOrder.DESC);
searchRequestBuilder.setFrom(0);
searchRequestBuilder.setSize(1);
//获取 查询结果
SearchResponse searchResponse = searchRequestBuilder.get();
//获取到命中数据 Hits 命中数据
SearchHits hits = searchResponse.getHits();
List<Product> products = new ArrayList<>();
//获取到循环迭代器
Iterator<SearchHit> iterator = hits.iterator();
while(iterator.hasNext()){
//获取到下一条数据
SearchHit next = iterator.next();
//返回高亮字段的集合
Map<String, HighlightField> highlightFields = next.getHighlightFields();
//获取到需要的高亮字段
HighlightField productName = highlightFields.get("productName");
Map<String, Object> sourceAsMap = next.getSourceAsMap();
Product product = new Product();
product.setProductId((Integer) sourceAsMap.get("productId"));
Text[] fragments = productName.fragments();
product.setProductName(fragments[0].toString());
product.setProductDesc((String) sourceAsMap.get("productDesc"));
products.add(product);
}
return products;
}
dao层采取JPA写法
/**
* JPA写法
*/
public interface ProductRepository extends ElasticsearchCrudRepository<Product,Integer> {
/**
* 根据产品名称 查询产品
* @param ProductName
* @return
*/
Product findByProductName(String ProductName);
}