Mysql:
分类: 关系型数据库
概述: mysql在存储数据时,数据和数据之间有一定的关联关系
存储介质: 存放在硬盘上
优点: 不会导致数据丢失
缺点: 执行效率低
硬盘 ---> 内存 ---> CPU
事务控制,这也是他没被替换掉的原因
redis:
分类: 非关系型数据库
概述: 数据在存储时,数据和数据之间没有关联关系
存储介质: 内存
优点: 执行效率高
缺点: 可能会导致数据丢失
ElasticSearch: 灵活的搜索
分类: 非关系型数据库
概述: ES专门用于对海量数据的搜索
存储介质: 内存
优点: 搜索效率高
数据库排行查询网址:https://db-engines.com/
在模糊查询中,由于索引失效,mysql的查询效率太过低下。
【elasticsearch】
elasticsearch是一款非常强大的开源搜索引擎,具备非常多强大功能,可以帮助我们从海量数据中快速找到需要的内容.
【ELK】
elasticsearch结合kibana、Logstash、Beats,也就是elastic stack(ELK)。被广泛应用在日志数据分析、实时监控等领域:而elasticsearch是elastic stack的核心,负责存储、搜索、分析数据。
【Lucene】
elasticsearch底层是基于lucene来实现的。
Lucene是一个Java语言的搜索引擎类库,是Apache公司的顶级项目,由DougCutting于1999年研发。 官网:https://lucene.apache.org/
【优点】
检索数据非常快
【缺点】
【正向索引】
正向索引是最传统的,根据id索引的方式。但根据词条查询时,必须先逐条获取每个文档,然后判断文档中是否包含所需要的词条,是根据文档找词条的过程. 优点: 可以给多个字段创建索引 根据索引字段搜索、排序速度非常快 缺点: 根据非索引字段,或者索引字段中的部分词条查找时,只能全表扫描。
【倒排索引】
倒排索引则相反,是先找到用户要搜索的词条,根据词条得到保护词条的文档的id,然后根据id获取文档。是根据词条找文档的过程。 优点: 根据词条搜索、模糊搜索时,速度非常快 缺点: 只能给词条创建索引,而不是字段 无法根据字段做排序
【索引库】
索引(Index),就是相同类型的文档的集合。类似于mysql中的表
【mapping映射】
映射(mapping),是索引中文档的字段约束信息,类似mysql表的结构约束。
【文档】
文档(Document),就是一条条的数据,类似数据库中的行(Row),文档都是JSON格式
【词条】
词条(Term),对文档数据或用户搜索数据,利用某种算法分词,得到的具备含义的词语就是词条。
可视化工具,在浏览器输入DSL语句即可查看ES中的内容。
【索引库操作】
【创建索引库】
PUT /索引库名称
{
"mappings": {
"properties": {
"字段名":{
"type": "text",
"analyzer": "ik_smart"
},
"字段名2":{
"type": "keyword",
"index": "false"
},
"字段名3":{
"properties": {
"子字段": {
"type": "keyword"
}
}
}
}
}
}
【查看索引库】
GET /索引库名
【删除索引库】
DELETE /索引库名
【修改索引库(追加)】
PUT /索引库名/_mapping
{
"properties":{
"新字段":{
"type":"数据类型(integer)"
}
}
}
【文档操作】
【新增文档】
POST /索引库名/_doc/文档id(不给会随机生成id)
{
"字段1": "值1",
"字段2": "值2",
"字段3": {
"子属性1": "值3",
"子属性2": "值4"
}
}
【查看文档】
GET /索引库名/_doc/文档id
【删除文档】
DELETE /索引库名/_doc/文档id
【修改文档】
【全量修改】
PUT /索引库名/_doc/文档id
{
"字段1": "值1",
"字段2": "值2"
}
【增量修改】
POST /索引库名/_update/文档id
{
"doc": {
"字段名": "新的值"
}
}
【导入依赖】
<dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> </dependency>
【与版本对应】
<properties> <java.version>1.8</java.version> <elasticsearch.version>7.12.1</elasticsearch.version> </properties>
【初始化连接&关闭连接】
private RestHighLevelClient client;
// 创建连接
@BeforeEach
void setUp() {
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://192.168.248.222:9200")
));
}
// 关闭连接
@AfterEach
void tearDown() throws IOException {
this.client.close();
}
【索引库操作】
【创建索引库】
// 创建索引库
@Test
public void createIndex() throws IOException {
// 1.创建请求语义对象
CreateIndexRequest request = new CreateIndexRequest("hotel");
// 添加 source
request.source(HotelConstants.MAPPING_TEMPLATE, XContentType.JSON);
// 2.发送请求
CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
// 3.解析响应
boolean flag = response.isAcknowledged();
// 打印结果
System.out.println(flag);
}
【删除索引库】
// 删除索引库
@Test
public void deleteIndex() throws IOException {
// 1.创建请求语义对象
DeleteIndexRequest request = new DeleteIndexRequest("hotel");
// 2.发送请求
AcknowledgedResponse response = client.indices().delete(request, RequestOptions.DEFAULT);
// 3.解析响应
boolean flag = response.isAcknowledged();
// 打印结果
System.out.println(flag);
}
【查看索引库是否存在】
// 查看索引库是否存在
@Test
public void existsIndex() throws IOException {
// 1.创建请求语义对象
GetIndexRequest request = new GetIndexRequest("hotel");
// 2.发送请求
boolean flag = client.indices().exists(request, RequestOptions.DEFAULT);
// 3.解析响应
// 打印结果
System.out.println(flag);
}
【文档操作】
【添加文档数据】
@Autowired
private IHotelService hotelService;
// 添加文档数据
@Test
public void add() throws IOException {
// 1.根据id获取数据
Hotel hotel = hotelService.getById(36934L);
// 2.转换成 ES 对应的数据
HotelDoc hotelDoc = new HotelDoc(hotel);
// 3.转换成JSON
String hotelDocJson = JSON.toJSONString(hotelDoc);
// 4.创建请求语义对象
IndexRequest request = new IndexRequest("hotel");
request.id(hotel.getId() + "");
request.source(hotelDocJson, XContentType.JSON);
// 5.发送请求
IndexResponse response = client.index(request, RequestOptions.DEFAULT);
// 6.解析响应结果
DocWriteResponse.Result result = response.getResult();
System.out.println(result);
}
【查询文档数据】
// 查询文档数据
@Test
public void select() throws IOException {
// 1.创建请求语义对象
GetRequest request = new GetRequest("hotel","36934");
// 2.发送请求
GetResponse response = client.get(request, RequestOptions.DEFAULT);
// 3.解析响应结果
String json = response.getSourceAsString();
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println(hotelDoc);
}
【修改文档数据】
// 修改文档数据
@Test
public void update() throws IOException {
// 1.创建请求语义对象
UpdateRequest request = new UpdateRequest("hotel","36934");
request.doc(
"name", "7天连锁酒店(上海宝山路地铁站店)"
);
// 2.发送请求
UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
// 3.解析响应结果
DocWriteResponse.Result result = response.getResult();
System.out.println(result);
}
【删除文档数据】
// 删除文档数据
@Test
public void delete() throws IOException {
// 1.创建请求语义对象
DeleteRequest request = new DeleteRequest("hotel","36934");
// 2.发送请求
DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);
// 3.解析响应结果
DocWriteResponse.Result result = response.getResult();
System.out.println(result);
}
【批量添加】
@Autowired
private IHotelService hotelService;
// 批量添加文档数据
@Test
public void add() throws IOException {
// 1.批量查询酒店数据
List<Hotel> hotels = hotelService.list();
// 2.创建请求语义对象
BulkRequest request = new BulkRequest();
for (Hotel hotel : hotels) {
// 转换格式
HotelDoc hotelDoc = new HotelDoc(hotel);
String hotelDocJson = JSON.toJSONString(hotelDoc);
IndexRequest indexRequest = new IndexRequest("hotel");
indexRequest.id(hotel.getId() + "");
indexRequest.source(hotelDocJson, XContentType.JSON);
request.add(indexRequest);
}
// 5.发送请求
BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);
// 6.解析响应结果
RestStatus status = response.status();
System.out.println(status);
}
【查询所有】
GET /索引库名/_search
{
"query": {
"match_all": {
}
}
}
【全文检索查询】
【多字段】
GET /索引库名/_search
{
"query": {
"multi_match": {
"query": "内容",
"fields": ["字段1", "字段2"]
}
}
}
【单字段】
GET /hotel/_search
{
"query": {
"match": {
"字段": "值"
}
}
}
【精确查询】
【term查询】
GET /索引库名/_search
{
"query": {
"term": {
"字段": {
"value": "值"
}
}
}
}
【range查询】
GET /索引库名/_search
{
"query": {
"range": {
"字段": {
"gte": 10, // 这里的gte代表大于等于,gt则代表大于
"lte": 20 // lte代表小于等于,lt则代表小于
}
}
}
}
【地理坐标查询】
【矩形范围查询】
GET /索引库名/_search
{
"query": {
"geo_bounding_box": {
"字段": {
"top_left": { // 左上点
"lat": 31.1,
"lon": 121.5
},
"bottom_right": { // 右下点
"lat": 30.9,
"lon": 121.7
}
}
}
}
}
【附近/距离查询】
GET /索引库名/_search
{
"query": {
"geo_distance": {
"distance": "15km", // 半径
"字段": "31.21,121.5" // 圆心
}
}
}
【复合查询】
【算分函数查询】
GET /hotel/_search
{
"query": {
"function_score": {
"query": {
// 原始查询条件 根据BM25算法进行算分
"match": {
"all": "外滩"
}
},
"functions": [
{
// 过滤条件 符合条件重新算分
"filter": {
"term": {
"brand": "如家"
}
},
//算分函数 weight是常量值
"weight": 10
}
],
//加权模式 默认是multiply
"boost_mode": "sum"
}
}
}
【布尔查询】
GET /hotel/_search
{
"query": {
"bool": {
//必须匹配
"must": [
{
"match": {
"all": "上海"
}
}
],
//选择匹配
"should": [
{
"term": {
"brand": {
"value": "皇冠假日"
}
}
},
{
"term": {
"brand": "华美达"
}
}
],
//必须不匹配 不参与算分
"must_not": [
{
"range": {
"price": {
"lte": 400
}
}
}
],
//必须匹配 不参与算分
"filter": [
{
"geo_distance": {
"distance": "10km",
"location": {
"lat": 31.21,
"lon": 121.5
}
}
}
]
}
}
}
【排序】
【普通字段】
GET /索引库名/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"字段": "desc" // 排序字段、排序方式ASC、DESC
}
]
}
【地理坐标】
GET /hotel/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"_geo_distance": {
"地理坐标相关字段": {
"lat": 31.21,
"lon": 121.5
},
"order":"asc",
//单位
"unit":"km"
}
}
]
}
【分页】
【基本分页】
GET /hotel/_search
{
"query": {
"match_all": {}
},
"from": 0, // 分页开始的位置,默认为0
"size": 10, // 期望获取的文档总数
"sort": [
{"price": "asc"}
]
}
【深度分页】
【高亮】
GET /hotel/_search
{
"query": {
"match": {
"FIELD": "TEXT" // 查询条件,高亮一定要使用全文检索查询
}
},
"highlight": {
"fields": { // 指定要高亮的字段
"FIELD": {
"pre_tags": "<em>", // 用来标记高亮字段的前置标签
"post_tags": "</em>", // 用来标记高亮字段的后置标签
"require_field_match": "false"
}
}
}
}
【查询所有】
// 查询所有--match all
@Test
public void matchAll() throws IOException {
// 1.创建 SearchRequest 对象
SearchRequest request = new SearchRequest("hotel");
// 2.组织 DSL 参数
request.source()
.query(QueryBuilders.matchAllQuery());
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应结果
handleResponse(response);
}
【全文检索查询】
// 全文检索查询--match
@Test
public void match() throws IOException {
// 1.创建 SearchRequest 对象
SearchRequest request = new SearchRequest("hotel");
// 2.组织 DSL 参数
request.source()
.query(QueryBuilders.matchQuery("all","如家"));
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应结果
handleResponse(response);
}
【精确查询】
【term查询】
// 精确查询--term
@Test
public void term() throws IOException {
// 1.创建 SearchRequest 对象
SearchRequest request = new SearchRequest("hotel");
// 2.组织 DSL 参数
request.source()
.query(QueryBuilders.termQuery("city","杭州"));
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应结果
handleResponse(response);
}
【range查询】
// 范围查询--range
@Test
public void range() throws IOException {
// 1.创建 SearchRequest 对象
SearchRequest request = new SearchRequest("hotel");
// 2.组织 DSL 参数
request.source()
.query(QueryBuilders.rangeQuery("price").gte(500).lte(1000));
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应结果
handleResponse(response);
}
【复合查询】
【布尔查询】
// 布尔查询--bool
@Test
public void bool() throws IOException {
// 1.创建 SearchRequest 对象
SearchRequest request = new SearchRequest("hotel");
// 2.组织 bool 查询参数
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
boolQuery.must(QueryBuilders.termQuery("city", "杭州"));
boolQuery.filter(QueryBuilders.rangeQuery("price").lt(1000));
// 3.组织 DSL 参数
request.source()
.query(boolQuery);
// 4.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 5.解析响应结果
handleResponse(response);
}
【排序分页】
// 排序、分页--sort from size
@Test
public void sortAndPage() throws IOException {
// 1.创建 SearchRequest 对象
SearchRequest request = new SearchRequest("hotel");
// 2.组织 DSL 参数
// 查询所有
request.source().query(QueryBuilders.matchAllQuery());
// 前 20条
request.source().from(0).size(20);
// 按价格升序
request.source().sort("price", SortOrder.ASC);
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应结果
handleResponse(response);
}
【高亮】
// 高亮--highlights
@Test
public void highlights() throws IOException {
// 1.创建 SearchRequest 对象
SearchRequest request = new SearchRequest("hotel");
// 2.组织 DSL 参数
// 查询所有带有如家
request.source().query(QueryBuilders.matchQuery("all","如家"));
// 高亮处理
request.source().highlighter(new HighlightBuilder()
.field("name")
.requireFieldMatch(false));
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应结果 -- 高亮特殊处理
handleResponse(response);
}
【响应结果解析】
// 响应结果解析
private void handleResponse(SearchResponse response) {
// 4.解析响应结果
SearchHits searchHits = response.getHits();
// 查询总条数
long total = searchHits.getTotalHits().value;
System.out.println("查询总条数:" + total);
// 查询结果数组
SearchHit[] hits = searchHits.getHits();
// 遍历
for (SearchHit hit : hits) {
// 得到json
String hotelDocJson = hit.getSourceAsString();
// 转换成Java对象
HotelDoc hotelDoc = JSON.parseObject(hotelDocJson, HotelDoc.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();
hotelDoc.setName(name);
}
}
// 打印结果
System.out.println(hotelDoc);
}
}
GET /hotel/_search
{
"query": {//限定聚合条件
"range": {
"price": {
"lte": 200 // 只对200元以下的文档聚合
}
}
},
"size": 0, // 设置size为0,结果中不包含文档,只包含聚合结果
"aggs": { // 定义聚合
"brandAgg": { //给聚合起个名字
"terms": { // 聚合的类型,按照品牌值聚合,所以选择term
"field": "brand", // 参与聚合的字段
"order": {
"_count": "asc" // 按照_count升序排列
},
"size": 20 // 希望获取的聚合结果数量
},
"aggs": { // 是brands聚合的子聚合,也就是分组后对每组分别计算
"score_stats": { // 聚合名称
"stats": { // 聚合类型,这里stats可以计算min、max、avg等
"field": "score" // 聚合字段,这里是score
}
}
}
}
}
}
【聚合查询】
// 聚合查询--aggregation
@Test
public void aggregation() throws IOException {
// 1.创建 SearchRequest 对象
SearchRequest request = new SearchRequest("hotel");
// 2.组织 DSL 参数
request.source().size(0);
request.source().aggregation(AggregationBuilders
.terms("brand_agg")
.field("brand")
.order(BucketOrder.aggregation("_count",true))
.size(20));
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应结果
handleResponse(response);
}
【响应结果解析】
// 响应结果解析
private void handleResponse(SearchResponse response) {
// 4.解析聚合响应结果
Aggregations aggregations = response.getAggregations();
// 根据名称获得聚合结果
Terms brandTerms = aggregations.get("brand_agg");
// 获取桶
List<? extends Terms.Bucket> buckets = brandTerms.getBuckets();
// 遍历
for (Terms.Bucket bucket : buckets) {
// 获取品牌信息
String brandName = bucket.getKeyAsString();
long count = bucket.getDocCount();
System.out.println(brandName+":"+count);
}
}