ElasticSearch快速入门

ElasticSearch基础知识
一、核心概念

基础概念描述
索引(index)索引是具有相似结构的文档的集合, 可以把索引当作是数据库中的表, 比如可以有一个商品分类索引, 订单索引.每个索引都要有唯一的名称, 名称要小写, 通过索引名称来执行索引、搜索、更新和删除等操作.可以有任意多个索引, 只要保证名称不同即可.
类型(type)type是index的逻辑分类, 在ES 6.x版本之前, 每个索引中可以定义一个或多个type, 而在6.X版本之后, 一个index中只能定义一个type.一种type一般被定义为具有一组公共field的document, 比如对博客系统中的数据建立索引, 可以定义用户数据type, 博客数据type, 评论数据type, 也就是每个document都必须属于某一个具体的type, 也就是说每个document都有_type属性.
文档(document)t文档是存储在ES中的一个个JSON格式的字符串, 是ES索引中的最小数据单元, 由field(字段)构成.一个document可以是一条商品分类数据, 一条订单数据, 例如: #book document{“book_id”: “1”,“book_name”: “Thinking in Java(Java 编程思想)”,“book_desc”: “Java学习者不得不看的经典书籍”,“book_price”: 108.00,“category_id”: “5”}
映射(mapping)类似于关系数据库中的Table结构, 每个index都有一个映射: 定义索引中每个字段的类型.所有文档在写进索引之前都会先进行分析, 如何对文本进行分词、哪些词条又会被过滤, 这类行为叫做映射(mapping).映射可以提前定义, 也可以在第一次存储文档时自动识别. 一般由用户自己定义规则.
字段(filed)字段可以是一个简单的值(如字符串、数字、日期), 也可以是一个数组, 还可以嵌套一个对象或多个对象.字段类似于关系数据库中表数据的列, 每个字段都对应一个类型.可以指定如何分析某一字段的值, 即对field指定分词器.

ES的索引中, 各概念的关系为: Field --> Document --> Type --> Index, 索引结构图如下:
在这里插入图片描述
在这里插入图片描述
更多内容参考
官方帮助文档 :
https://www.elastic.co/guide/index.html
牛人博客:
https://www.cnblogs.com/shoufeng/p/9887327.html 上述表格文字和图片截取自此篇博客。
https://www.cnblogs.com/qdhxhz/p/11448451.html 可以了解倒排索引和分片的知识

二、准备工作
版本环境:ElastciSearch 7.12.1 Ik分词器 7.12.1 Kibana 7.12.1
在SpringBoot中操作elasticsearch的准备工作
(1).引入es的RestHighLevelClient依赖:

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>

(2).SpringBoot默认的ES版本有可能并不是7.12.1,我们需要覆盖默认的ES版本,一定要保证版本之间保持一致:

<properties>
    <elasticsearch.version>7.12.1</elasticsearch.version>
</properties>

(3).初始化RestHighLevelClient:

RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
        HttpHost.create("http://xxx.xxx.xxx.xxx:9200"),HttpHost.create("服务器地址"), . . . //可以添加多个做集群设置,以逗号分割
));

三、索引库操作
1、增
DSL语句:

PUT /索引库名称
{
  "mappings": {
    "properties": {
      "字段名":{
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "字段名2":{
        "type": "keyword",
        "index": "false"
      },
      "字段名3":{
        "properties": {
          "子字段": {
            "type": "keyword"
          }
        }
      },
      // ...略
    }
  }
}

Java代码:

// 1.创建Request对象
CreateIndexRequest request = new CreateIndexRequest("索引库名称");
// 2.准备请求的参数:DSL语句
request.source(MAPPING_TEMPLATE, XContentType.JSON);        //MAPPING_TEMPLATE 创建索引库的DSL语句,一般很长,所以配置为静态常量字符串
// 3.发送请求
client.indices().create(request, RequestOptions.DEFAULT);

2、删
DSL语句:DELETE /索引库名

Java代码:

// 1.创建Request对象
DeleteIndexRequest request = new DeleteIndexRequest("索引库名称");
// 2.发送请求
client.indices().delete(request, RequestOptions.DEFAULT);

3、判断索引库是否存在
DSL语句获取索引库:GET /hotel

Java代码:

// 1.创建Request对象
GetIndexRequest request = new GetIndexRequest("索引库名称");
// 2.发送请求
boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
// 3.输出
System.err.println(exists ? "索引库已经存在!" : "索引库不存在!");

四、文档操作
1、增
DSL语句:

POST /{索引库名}/_doc/1
{
    "name": "Chen",
    "age": 22
}

Java代码:

// 1.创建Request对象
IndexRequest request = new IndexRequest("索引库名称").id("文档Id");
// 2.准备参数:JSON格式的数据
request.source(“JSON数据”, XContentType.JSON);
// 3.发送请求
client.index(request, RequestOptions.DEFAULT);

批量导入文档

// 批量查询数据
List<Person> persons= personService.list();
// 1.创建Request
BulkRequest request = new BulkRequest();
// 2.准备参数,添加多个新增的Request
for (Person person: persons) {
      request.add(new IndexRequest("person")
                 .id(person.getId().toString())
                 .source(JSON.toJSONString(person), XContentType.JSON));
    }
// 3.发送请求
client.bulk(request, RequestOptions.DEFAULT);

2、删
DSL语句:DELETE /索引库名称/_doc/{id}

Java代码:

// 1.准备Request
DeleteRequest request = new DeleteRequest("索引库名称", "文档ID");
// 2.发送请求
client.delete(request, RequestOptions.DEFAULT);

3、改
在ES中有两种修改方式:
(1)全量修改:本质是先根据id删除,再新增
(2)增量修改:修改文档中的指定字段值
在RestClient的API中,全量修改与新增的API完全一致,判断依据是ID:
(1)如果新增时,ID已经存在,则修改
(2)如果新增时,ID不存在,则新增

1.准备Request
UpdateRequest request = new UpdateRequest ("索引库名称", "文档ID");
// 2.准备请求参数
request.doc(
        "name", "King",
        "age", "666"
 );
// 3.发送请求
client.update(request, RequestOptions.DEFAULT);

4、查
DSL语句:GET /索引库名称/_doc/{id}

Java代码:

// 1.准备Request
GetRequest request = new GetRequest("索引库名称", "文档Id");
// 2.发送请求,得到响应
GetResponse response = client.get(request, RequestOptions.DEFAULT);
// 3.解析响应结果
String json = response.getSourceAsString();
Person person= JSON.parseObject(json, Person.class);
System.out.println(person);

5、全文检索
match查询:单字段查询

//match查询DSL语句:
GET /索引库名称/_search
{
  "query": {
    "match": {
      "FIELD": "TEXT" //需要匹配查询的字段
    }
  }
}

multi_match查询:多字段查询,任意一个字段符合条件就算符合查询条件

//mulit_match查询DSL语句:
GET /索引库名称/_search
{
  "query": {
    "multi_match": {
      "query": "TEXT",
      "fields": ["FIELD1", " FIELD12"]   //可以匹配多个查询条件
    }
  }
}

Java代码:

// 1.准备Request
SearchRequest request = new SearchRequest("索引库名称");
// 2.准备DSL
request.source()
    .query(QueryBuilders.matchQuery("查询字段", "字段值"));
 //.query(QueryBuilders.multiMatchQuery("字段值", "Filed1","Filed2",...));
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应
handleResponse(response);

6、排序
DSL语句:

GET /索引库名称/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "FIELD": "desc"  // 排序字段、排序方式ASC、DESC
    }
  ]
}

Java代码:

// 页码,每页大小
int page = 1, size = 5;
// 1.准备Request
SearchRequest request = new SearchRequest("索引库名称");
// 2.准备DSL
// 2.1.query
request.source().query(QueryBuilders.matchAllQuery());
// 2.2.排序 sort
request.source().sort("字段名", SortOrder.ASC);
// 2.3.分页 from、size
request.source().from((page - 1) * size).size(5);
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应
handleResponse(response);

7、分页
DSL语句:

GET /索引库名称/_search
{
  "query": {
    "match_all": {}
  },
  "from": 0, // 分页开始的位置,默认为0
  "size": 10, // 期望获取的文档总数
  "sort": [
    {"FIELD": "asc"}
  ]
}

java代码见上一条。

8、精确查询
term:根据词条精确值查询

// term查询
GET /索引库名称/_search
{
  "query": {
    "term": {
      "FIELD": {
        "value": "VALUE"
      }
    }
  }
}

range:根据值的范围查询

// range查询
GET /索引库名称/_search
{
  "query": {
    "range": {
      "FIELD": {
        "gte": 10, // 这里的gte代表大于等于,gt则代表大于
        "lte": 20 // lte代表小于等于,lt则代表小于
      }
    }
  }
}

Java代码:

  // 1.准备Request
    SearchRequest request = new SearchRequest("索引库名称");
    // 2.准备DSL
    // 2.1.准备BooleanQuery,布尔查询是用must、must_not、filter等方式组合其它查询
    BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
    // 2.2.添加term
    boolQuery.must(QueryBuilders.termQuery("字段名", "字段值"));
    // 2.3.添加range
    boolQuery.filter(QueryBuilders.rangeQuery("字段名").lte(字段值));
    request.source().query(boolQuery);
    // 3.发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 4.解析响应
    handleResponse(response);

9、聚合查询
DSL语句:

#聚合查询
GET /索引库名称/_search
{
  "size":0,
  "aggs": {
    "随便起一个聚合名称": {
      "terms": {
        "field": "字段名",
        "size": 10
      }
    }
  }
}	
#聚合查询,自定义排序规则
GET /索引库名称/_search
{
  "query": {
    "range": {
      "字段名": {
        "lte": 200
      }
    }
  }, 
  "size": 0,
  "aggs": {
    "随便起一个聚合名称": {
      "terms": {
        "field": "字段名",
        "size": 10,
        "order": {
          "_count": "asc"
        }
      }
    }
  }
}	
#Metric聚合语法(avg,max,min,stat等)
GET /索引库名称/_search
{
  "size": 0,
  "aggs": {
    "随便起一个聚合名称": {
      "terms": {
        "field": "字段名",
        "size": 10,
        "order": {
          "随便起一个子聚合名称.avg": "asc"
        }
      },
      "aggs": {
        "随便起的子聚合名称": {
          "stats": {
            "field": "score"
          }
        }
      }
    }
  }
}

Java代码:

// 聚合查询
    @Test
    public void testAggregation() throws IOException{
        // 准备request
        SearchRequest request = new SearchRequest("索引库名称");
        //DSL语句
        request.source().size(0);
        request.source().aggregation(
                AggregationBuilders.terms("聚合名称")
                .size(显示结果数).field("字段名"));
        // 发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //获取聚合结果
        Aggregations aggregations = response.getAggregations();
        //获取terms
        Terms terms = aggregations.get("聚合名称");
        //获取buckets
        List<? extends Terms.Bucket> buckets = terms.getBuckets();
        //遍历取出key值
        for (Terms.Bucket bucket : buckets) {
            String key = bucket.getKeyAsString();
            System.out.println(key);
        }  
    }

10、查询结果中关键字高亮显示

#高亮显示
GET /索引库名称/_search
{
  "query": {
    "match": {
      "字段名": "字段值"
    }
  },
  "highlight": {
    "fields": {
      "字段名": {
      }
    }
  }
}

Java代码:

// 高亮显示
    @Test
    public void testHighlight() throws IOException {
        // 1.准备Request
        SearchRequest request = new SearchRequest("索引库名称");
        // 2.准备DSL
        // 2.1.query
        request.source().query(QueryBuilders.matchQuery("字段名", "字段值"));
        // 2.2.高亮
        request.source().highlighter(new HighlightBuilder().field("字段名").requireFieldMatch(false));
        // 3.发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 4.解析响应
        handleResponse(response);
    }
private void handleResponse(SearchResponse response) {
		// 4.解析响应
		SearchHits searchHits = response.getHits();
		// 4.1.获取总条数
		long total = searchHits.getTotalHits().value;
		System.out.println("共搜索到" + total + "条数据");
		// 4.2.文档数组
		SearchHit[] hits = searchHits.getHits();
		// 4.3.遍历
		for (SearchHit hit : hits) {
			// 获取文档source
			String json = hit.getSourceAsString();
			// 反序列化
			Person person= JSON.parseObject(json, Person.class);
			Map<String, HighlightField> highlightFields = hit.getHighlightFields();
			if (!CollectionUtils.isEmpty(highlightFields)) {
				// 根据字段名获取高亮结果
				HighlightField highlightField = highlightFields.get("name");
				if (highlightField != null) {
					// 获取高亮值
					String name = highlightField.getFragments()[0].string();
					// 覆盖非高亮结果
					person.setName(name);
				}
			}
			System.out.println("person= " + person);
		}
	}

五、数据存储、备份和恢复
后续补充。。。。

PS:自学完黑马关于ES的教学做的简单总结,不喜勿喷,谢谢。传送门

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值