文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html

1、elasticsearch安装启动
看见访问localhost:9200能见到for search说明正常
2、安装head插件
elasticsearch的可视化工具 端口为9100
3、整合kibana
http://localhost:5601/app/kibana kibana以来node.js,需要安装
kibana汉化,在kibana.yml中加i18n.locale: “zh-CN”
kibana.yml也可以配置elasticsearch服务的地址和端口等。
4、与java整合
与springboot整合
1、添加jar包
2、yml添加配置文件
cluster-nodes: 127.0.0.1:9300 # es的连接地址及端口号
cluster-name: elastic # es集群的名称
这里为什么是9300端口不是9200端口呢?
9200是给http协议通讯用的,9300是集群中通讯用的用的tcp协议,RPC框架都是用的tcp协议。
两者协议区别:

概念
正排索引
也就是一个id(索引)对应一条数据传统的类似mysql数据库,查询时通过索引能快速查询到数据,但是模糊查询呢,只能通过遍历数据库,一个个去匹配,严重影响效率。

倒排索引
文档数据去查询id的索引,通过数据“student”的查询到索引为1,2,3

elasticsearch基本操作
1)GET:获取请求对象的当前状态。
2)POST:改变对象的当前状态。
3)PUT:创建一个对象。
4)DELETE:销毁对象。
5)HEAD:请求获取对象的基础信息。

1、索引操作
PUT(幂等)
创建索引(等同于创建数据库)http://127.0.0.1:9200/shopping PUT方式
GET
查看索引 http://127.0.0.1:9200/shopping GET方式
查看所有索引 http://127.0.0.1:9200/_cat/indices?v 类似(show tables)
DELETE(幂等)
删除索引 http://127.0.0.1:9200/shopping DELETE 方式
POST
向索引添加文档或者修改文档 http://127.0.0.1:9200/shopping/_doc
返回数据解析

{
 "_index"【索引】: "shopping",
 "_type"【类型-文档】: "_doc",
 "_id"【唯一标识】: "Xhsa2ncBlvF_7lxyCE9G", #可以类比为 MySQL 中的主键,随机生成
 "_version"【版本】: 1,
 "result"【结果】: "created", #这里的 create 表示创建成功
 "_shards"【分片】: {
 "total"【分片 - 总数】: 2,
 "successful"【分片 - 成功】: 1,
 "failed"【分片 - 失败】: 0
 },
 "_seq_no": 0,
 "_primary_term": 1
}

这里的文档_type是死的 只能写_doc,后面可以添加自定义id比如:
http://127.0.0.1:9200/shopping/_doc /123
这样es系统的_id就是123了
注意:put和post区别
应为每次post请求不指定id的话都会创建一个文档并返回一个文档id,多次请求返回的id,这个id是es自动生成的,不是操作的同一个文档。
put请求因为是幂等的,发送创建文档的话只能针对同一个id的文档,所以这里不能使用,前面创建索引的话他是同一个所以可以使用。http://127.0.0.1:9200/shopping/_doc /123 PUT方式,这样的话可以访问。

2、文档操作
修改和新增文档
指定id的创建文档(不指定id会自动生成一个id)
http://127.0.0.1:9200/shopping(索引名称)/_doc(文档类型只能是_doc)/123(文档id) POST/PUT方式
http://127.0.0.1:9200/shopping/_doc/123 POST方式
这里注意:json格式发送的话会整体覆盖。
如果只想修改文档中的一个字段
http://127.0.0.1:9200/shopping/_update/123 POST方式
这里只会修改body体中的字段

删除文档
http://127.0.0.1:9200/shopping/_doc/123 DELETE方式
根据条件删除多个文档
http://127.0.0.1:9200/shopping/_delete_by_query POST方式
body中添加条件

{
	 "query":{
		 "match":{
		 "price":4000.00
		 }
	 } 
 }

查询文档(重点)
指定id查询
http://127.0.0.1:9200/shopping(索引名称)/_doc(文档类型只能是_doc)/123(文档id) GET方式

http://127.0.0.1:9200/shopping/_search GET方式

{
    "query" : {
    	//查询所有
	        "match_all" : {}
        //条件查询
	        "match":{
			"price":4000.00	
		}	
}

分页排序查询

{
    "query" : {
    	//查询所有
	        "match_all" : {}
		},
		"from":0,
		"size":2 
		//需要显示的key内容
		"_source":{"title"}
		//根据price降序排序
		"sort":{
			"price":{
				"order":"desc"
			}
		}
}

多条件查询过滤查询

{
    "query" : {
    		"bool":{
    			//must表示必须都满足,should表示满足一个
    			"must"//"should":[
					{
						"match" : {
							"category":"小米"
							"category":"米"
						}
					},
					{
						"match" : {
							"category":"华为"
						}
					}
				],
				//过滤查询price大于5000
				"filter":{
					"range":{
						"price":{
							"gt":5000
						}
					}
				}
    		}   
		}
}

全文检索和完全匹配高亮查询

{
    "query" : {
    //全文检索
       "match":{
			//文档中没有小华为什么也能查询到?es默认做了分词,分别查询”小“和”华“
			"category":"小华"	
		}
	//完全匹配
		"match_phrase":{
			//这里只能查询到文档中有小华的文档了
			"category":"小华"	
		}
	//高亮查询
		"highlight":{
			//哪些字段需要高亮显示
			"fields":{
				"category":{}
			}
		}		
}

聚合操作

{	
	//分组
	"aggs":{
		"price_group":{ //分组名称随意取
			"terms":{
				"field":"price" //分组字段
			}
		}
	}	
}

这里解释为什么不创建索引聚合会报错(text类型默认禁用Fieddata)

索引(类似数据库表的字段)
创建索引(也可以增加索引,但是不支持修改)
http://127.0.0.1:9200/student/_mapping post方式

{
 "properties": {
 "name":{
 "type": "text",
 "index": true
 },
 "sex":{
 "type": "text",
 "index": false
 },
 "age":{
 "type": "long",
 "index": false
 }
 } }

查看索引
http://127.0.0.1:9200/student/_mapping GET方式
类似数据库表的数据类型,你不创建的话es会默认给你个索引类型字段名:
索引的数据类型
type:类型,Elasticsearch 中支持的数据类型非常丰富,说几个关键的:
String 类型,又分两种:
text:可分词
keyword:不可分词,数据会作为完整字段进行匹配
Numerical:数值类型,分两类
基本数据类型:long、integer、short、byte、double、float、half_float
浮点数的高精度类型:scaled_float
Date:日期类型
Array:数组类型
Object:对象

其他属性
index:是否索引,默认为 true,也就是说你不进行任何配置,所有字段都会被索引。
true:字段会被索引,则可以用来进行搜索
false:字段不会被索引,不能用来搜索

store:是否将数据进行独立存储,默认为 false
原始的文本会存储在_source 里面,默认情况下其他提取出来的字段都不是独立存储的,是从_source 里面提取出来的。当然你也可以独立的存储某个字段,只要设置"store": true 即可,获取独立存储的字段要比从_source 中解析快得多,但是也会占用更多的空间,所以要根据实际业务需求来设置。

analyzer:分词器,这里的 ik_max_word 即使用 ik 分词器。

整合java api
导入pom

<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>7.6.1</version>
</dependency>
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.6.1</version>
</dependency>
class EsstudyApplicationTests {

    @Test
    void contextLoads()throws Exception  {
        //连接
        RestHighLevelClient esClient = new RestHighLevelClient(
                RestClient.builder(new HttpHost("localhost",9200,"http"))
        );
//------------------------------------------------索引------------------------------------------------
        //创建索引
//        CreateIndexRequest request = new CreateIndexRequest("javauser");
//        CreateIndexResponse createIndexResponse = esClient.indices().create(request, RequestOptions.DEFAULT);
                    //响应状态
//        boolean acknowledged = createIndexResponse.isAcknowledged();
//        System.out.println(acknowledged);

        //查询索引
//        GetIndexRequest request = new GetIndexRequest("user");
//        GetIndexResponse getIndexResponse = esClient.indices().get(request, RequestOptions.DEFAULT);
//        System.out.println(getIndexResponse.getAliases());
//        System.out.println(getIndexResponse.getMappings());
//        System.out.println(getIndexResponse.getSettings());

        //删除索引
//      DeleteIndexRequest request = new DeleteIndexRequest("user");
//      AcknowledgedResponse delete = esClient.indices().delete(request, RequestOptions.DEFAULT);
//      System.out.println(delete.isAcknowledged());

//------------------------------------------------文档------------------------------------------------
        //文档增加数据
//        IndexRequest request = new IndexRequest();
//        request.index("user").id("1001");   //索引库和id
//        User user = new User();
//        user.setName("张三");
//        user.setSex("男");
//        user.setTel("das");
//        user.setMoney((long)312);
//        //必须转成json格式
//        String userjson = JSON.toJSONString(user);
//        request.source(userjson, XContentType.JSON);
//        IndexResponse response = esClient.index(request, RequestOptions.DEFAULT);
//        System.out.println(response.getResult());

        //修改文档
//        UpdateRequest request = new UpdateRequest();
//        request.index("user").id("1001");   //索引库和id
//        request.doc(XContentType.JSON,"sex","女的");
//        UpdateResponse response = esClient.update(request, RequestOptions.DEFAULT);
//        System.out.println(response.getResult());

        //文档查询
        //1.创建请求对象
//        GetRequest request = new GetRequest().index("user").id("1001");
//        //2.客户端发送请求,获取响应对象
//        GetResponse response = esClient.get(request, RequestOptions.DEFAULT);
//         //3.打印结果信息
//        System.out.println("_index:" + response.getIndex());
//        System.out.println("_type:" + response.getType());
//        System.out.println("_id:" + response.getId());
//        System.out.println("source:" + response.getSourceAsString());

        //删除文档
        //创建请求对象
//        DeleteRequest request = new DeleteRequest().index("user").id("1001");
//        //客户端发送请求,获取响应对象
//        DeleteResponse response = esClient.delete(request, RequestOptions.DEFAULT);
//        //打印信息
//        System.out.println(response.toString());

//------------------------------------------------批量操作------------------------------------------------

        //批量新增
//        BulkRequest request = new BulkRequest();
//        request.add(new IndexRequest().index("user").id("1001").source(XContentType.JSON, "name", "zhangsan"));
//        request.add(new IndexRequest().index("user").id("1002").source(XContentType.JSON, "name", "lisi"));
//        request.add(new IndexRequest().index("user").id("1003").source(XContentType.JSON, "name", "wangwu"));
//        //客户端发送请求,获取响应对象
//        BulkResponse responses = esClient.bulk(request, RequestOptions.DEFAULT);
//        //打印结果信息
//        System.out.println("took:" + responses.getTook());
//        System.out.println("items:" + responses.getItems());

        //批量删除
//        BulkRequest request = new BulkRequest();
//        request.add(new DeleteRequest().index("user").id("1001"));
//        request.add(new DeleteRequest().index("user").id("1002"));
//        request.add(new DeleteRequest().index("user").id("1003"));
//        //客户端发送请求,获取响应对象
//        BulkResponse responses = esClient.bulk(request, RequestOptions.DEFAULT);
//        //打印结果信息
//        System.out.println("took:" + responses.getTook());
//        System.out.println("items:" + responses.getItems());

//------------------------------------------------高级查询(分页,排序)------------------------------------------------
        // 创建搜索请求对象
        SearchRequest request = new SearchRequest();
        request.indices("user");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 查询所有数据
//        sourceBuilder.query(QueryBuilders.matchAllQuery());
        //matchPhraseQuery 查询,查询条件为关键字 不会分词查询   不要用termQuery是个坑
//        sourceBuilder.query(QueryBuilders.matchPhraseQuery("name", "果"));
        //会根据'小'  '米'  '小米'分词查询
//        sourceBuilder.query(QueryBuilders.matchQuery("category","小米"));

        // 分页查询
        // 当前页其实索引(第一条数据的顺序号),from
//        sourceBuilder.from(0);
        // 每页显示多少条 size
//        sourceBuilder.size(2);

        // 排序
//        sourceBuilder.sort("price", SortOrder.ASC);

        //查询字段过滤
//        String[] excludes = {};
//        String[] includes = {"title", "category"};
//        sourceBuilder.fetchSource(includes, excludes);

        //bool查询组合查询       matchQuery和matchPhraseQuery一个是分词查询,一个是精确的
//        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 必须包含
//        boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("money", "100"));
        // 一定不含
//        boolQueryBuilder.mustNot(QueryBuilders.matchPhraseQuery("title", "小华"));
        // 可能包含
//        boolQueryBuilder.should(QueryBuilders.matchQuery("title", "小米手机"));
//        sourceBuilder.query(boolQueryBuilder);

        //范围查询
//        RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("birth");
        // 大于等于
//        rangeQuery.gte("1992-11-12");
        // 小于等于
//        rangeQuery.lte("2000-11-12");
//        sourceBuilder.query(rangeQuery);

        //模糊查询
        //这种模糊查询支持text和keyword格式,不过text加?不起作用(可能原因是中文做了分词),只能加*
//        sourceBuilder.query(QueryBuilders.wildcardQuery("sex","男*"));
        //这种模糊查询支持text和keyword格式  text格式中文默认只能搜索一个单词,大概原因是默认对text做了分词,搜索两个字段没法查询到。而keyword没有做分词,所以只能精确查询到。
        //而且这里可以设置模糊度,默认是auto。
//        sourceBuilder.query(QueryBuilders.fuzzyQuery("sex","男"));

        //高亮
        //构建高亮字段
//        sourceBuilder.query(QueryBuilders.matchAllQuery());
//        HighlightBuilder highlightBuilder = new HighlightBuilder();
//        highlightBuilder.preTags("<font color='red'>");//设置标签前缀
//        highlightBuilder.postTags("</font>");//设置标签后缀
//        highlightBuilder.field("name");//设置高亮字段
        //设置高亮构建对象
//        sourceBuilder.highlighter(highlightBuilder);

        //聚合查询
        //最大
//        sourceBuilder.aggregation(AggregationBuilders.max("maxMoney").field("money"));
        //分组
//        sourceBuilder.aggregation(AggregationBuilders.terms("sex_groupby").field("sex"));
//        request.source(sourceBuilder);

        SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
        // 查询匹配
        SearchHits hits = response.getHits();
        System.out.println("took:" + response.getTook());
        System.out.println("timeout:" + response.isTimedOut());
        System.out.println("total:" + hits.getTotalHits());
        System.out.println("MaxScore:" + hits.getMaxScore());
        System.out.println("hits========>>");
        for (SearchHit hit : hits) {
        //输出每条查询的结果信息
            System.out.println(hit.getSourceAsString());
        }
        System.out.println("<<========");
        //关闭客户端
        esClient.close();

    }

}