Elasticsearch介绍及与项目整合

Elasticsearch介绍及与项目整合

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);
}

你可能感兴趣的:(spring,boot,Java,elasticsearch,java,spring,boot)