个人笔记-Elasticsearch

elasticsearch

ELK = Elasticsearch + Logstash + Kinbana

简介

elasticsearch是一个开源的高扩展的分布式全文检索引擎,其可以近乎实时的存储、检索数据,目的是通过简单的Restfut API来隐藏Lucene的复杂性

倒排索引/反向索引

倒排索引又称反向索引 倒排索引即通过vlaue获取key 而正向索引为通过key找value

采用Lucene倒排索引作为底层,该结构用于快速的全文搜索

1.将整句分拆为单词

2.将单词保存,对于每一条记录分别记录出现的位置

3.计算权重得分,当命中分数越高将被取出

记录
红海1,2,3,4,5
行动1,2,3
探索2,5
特别3,5
记录篇4
特工5
端口
9300

9300是TCP协议端口:通过tcp协议通讯,es集群之间是通过9300进行通讯,java客户端的方式也是tcp协议在9300端口上与集群进行通信

9200

9200是HTTP协议端口:主要用于外部通讯,外部使用Restful接口进行访问

ik分词器

数据类型

字符串:txt(会被分词器解析)、keyword(不会被分词器解析)

数值类型:long、integer、short、byte、double、flout、half float、scaled float

日期类型:date

布尔类型:boolean

二进制类型:binary

安装

# 创建外部文件 将内部文件挂载到mydata
mkdir -p /mydata/elasticsearch/config
mkdir -p /mydata/elasticsearch/data
#注意"http.host: 0.0.0.0"的空格
echo "http.host: 0.0.0.0">>/data/elasticsearch/config/elasticsearch.yml
# 启动容器并设置挂载目录
docker run --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms64m -Xmx512m" \
-v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \
-v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.4.2
# kinbana安装 注意ip为本机ip
docker run --name kibana -p 5601:5601 \
--link elasticsearch:elasticsearch \
-e ELASTICSERACH_HOSTS=http://192.168.205.128:9200 \
-d kibana:7.4.2

概念

名词关系型数据库简介
索引数据库不同类型的文档和文档属性的集合
类型索引可以定义一个或多个类型,文档必须属于一个类型
文档行/记录以json格式定义的特定方式的字段集合
字段
命令
元数据
元数据含义
_index索引名称
_type类型名称
_id唯一标识
_version版本
result处理方式
_seq_no、_primary_term用于乐观锁
found是否查询到
_cat
GET /_cat/nodes: 查看所有节点
GET /_cat/health: 查看es健康状况
GET /_cat/master: 查看主节点
GET /_cat/indices: 查看所有索引
新建

注意事项 es6以后不允许在一个index下建立多个type type将在之后版本退出

// customer为索引名称 external为类型 1为唯一标识
// PUT多次请求相同参数及标识 为update操作
PUT customer/external/1
{
    "name": "John Doe"
}

// POST请求若无携带标识 自动生成并返回 多次请求皆为created
// POST请求若有携带标识 则多次请求皆为update
POST customer/external
{
    "name": "John Doe"
}
查询
GET /customer/_doc/2

// 匹配的字段及值
"query": {
    "match_all": {} //匹配所有
}
// 单匹配
"query": {
    "match": {
        "address": "kings" // 单匹配 分词匹配
    }
}

"query": {
    "match_phrase": {
        "address": "mill lane" //单匹配 完整匹配
    }
}
// 多字段匹配 分词匹配
"query": {
    "multi_match": {
        "query": "mill",
        "fields": ["address", "city"]
    }
}
// bool匹配
"query": {
    "bool": {
        "must": [ ## 必须同时匹配gender = M及address = mill及年龄18-30
            {
                "match": {
                    "gender": "M"
                }
            },
            {
                "match": {
                    "address": "mill"
                }
            },
            {
                "range": {
                    "age": {
                        "gte": 18, // 年龄大于18 小于30
                        "lte": 30
                    }
                }
            }
        ],
        "must_not": [ // 必须不满足age = 38
            {
                "match": {
                    "age": "38"
                }
            }
        ],
        "should": [ // 应该匹配 可匹配可不匹配
            {
                "match": {
                    "lastname": "Wallace"
                }
            }
        ],
    }
}
// term查询 使用term查询非text字段 使用match查询text字段
"query": {
    "term": {
        "address": "990"
    }
  }
// keyword精确匹配
"query": {
    "term": {
        "address.keyword": "789 Madison Street"
    }
  }
// 排序
"sort": [
    {
        "account_number": "asc" //升序
    },
    {
        "balance": "desc" //降序
    }
]

// 分页
"from": 5,
"size": 2,
// 返回的字段
"_source": ["balance", "firstname"]
过滤

filter不贡献相关性得分

更新
// 更新操作若POST + _update则需放在"doc"里 若多次请求则result = noop(无操作)
POST /customer/_doc/2/_update
{
  "doc":{
    "name": "John Doew"
  }
}
// 更新操作若POST 不带_update则无需放在"doc"里 若多次请求则皆为update
POST /customer/_doc/2
{
   "name": "John Doew"
}
删除
// 删除文档
DELETE customer/external/1
// 删除所有
DELETE customer
高亮
"query": {
    "match": {
        "address": {
            "query": "mill"
        }
    }
},
"highlight": {
    "fields": {
        "address": {}  // 高亮的字段必须与query匹配的字段一样才能生效
    }
}
// 自定义高亮标签
"query": {
    "match": {
        "address": {
            "query": "mill"
        }
    }
},
"highlight": {
    "pre_tags": "<p class='key' style='clor:red' >", 
    "post_tags": "</p>", 
    "fields": {
        "address": {}
    }
}
批量
POST /customer/external/_bulk
{"index":{"_id":"1"}}
{"name":"John Doe"}
// 批量操作 每两条json为一组 一条指定标识 一条为具体数据
{"index":{"_id":"2"}}
{"name":"Jane Doe"}
聚合

聚合为基于已查到的数据,对查询数据进行再次分析

指标集合
"aggs": {
    "ageAgg": { // 聚合命名
        "terms": {
            "field": "age", // 聚合字段
            "size": 10 // 统计数量
        }
    },
    "ageAvg":{ 
        "avg": {
            "field": "age" //求平均值
        }
    }
}

// 子聚合
## 查询平均薪资按照年龄段聚合
"aggs": {
    "ageAgg": {
        "terms": {
            "field": "age",
            "size": 10
        },
        "aggs": { 
            "ageAvg": {
                "avg": {  
## max求最大值 min求最小值 sum求和 avg求平均数 value_count统计值 cardinality去重 stats统计(同时获得count min max avg sum) extended_stats拓展(同时获得count min max avg sum 平方和 方差 标准差 平均值加/减两个标准差的区间) percentiles百分比统计
                    "field": "balance"
                }
            }
        }
    }
}
## 按照年龄分布统计出不同性别的平均
"aggs": {
    "ageAgg": {
        "terms": {
            "field": "age",
            "size": 100
        },
        "aggs": {
            "genderAgg": {
                "terms": {
                    "field": "gender.keyword",
                    "size": 10
                },
                "aggs": {
                    "banlanceAvg": {
                        "avg": {
                            "field": "balance"
                        }
                    }
                }
            }
        }
    }
}
桶聚合

类似于group by分组 把满足相关特性的文档分到一个桶里

映射

es不能修改已经创建的映射 若需要修改 只能通过创建的映射 然后将数据迁移实现

PUT /my_index // 创建索引 再次请求error
{
  "mappings": {
    "properties": {
      "age": {"type": "integer"},
      "email": {"type": "keyword"},
      "name": {"type": "text"}
    }
  }
}

PUT /my_index/_mapping // 添加索引 再次请求error
{
  "properties": {
    "employee-id": {
      "type": "keyword",
      "index": false //是否参与索引 默认为true
    }
  }
} 

// 数据迁移
POST _reindex
{
  "source": {
    "index": "bank", // 旧索引
    "type": "account" //旧type
  },
  "dest": {
    "index": "newbank" //新索引
  }
}

分词

// 分词分析
POST _analyze
{
  "analyzer": "standard", // 使用默认分词器
  "text": "中华人民共华国"
}
POST _analyze
{
  "analyzer": "ik_smart", // 使用ik分词器
  "text": "中华人民共华国"
}
POST _analyze
{
  "analyzer": "ik_max_word", // 使用ik最大分词
  "text": "中华人民共华国"
}
ik分词器

https://github.com/medcl/elasticsearch-analysis-ik/releases?after=v7.7.0

ik版本需与elasticsearch版本一致

安装步骤

  • 将下载的压缩包放在外部映射路径 plugins/ik 下

  • 解压ik压缩包 unzip elasticsearch-analysis-ik-7.4.2.zip

  • 将分词存于fenci.txt文本内

  • 修改/mydata/elasticsearch/plugins/ik/config远程分词字典

image-20201222140059602

代码整合

elasticsearch-Rest-Client:官方客户端RestClient,封装了es操作,API层次分明,上手简单

<!-- es高级客户端 -->
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.4.2</version>
</dependency>
<!-- 引入高级client后 springboot依赖对es版本作了统一管理 需要进行修改 -->
<!-- 修改spring-boot-dependencies-2.0.3.RELEASE es版本-->
<!-- 注意若在A项目修改完dependencies版本之后 在B项目会自动关联修改 具体原因还未知 -->
<elasticsearch.version>7.4.2</elasticsearch.version>
// es配置文件
@Configuration
public class ElasticsearchConfig {

    public static final RequestOptions COMMON_OPTIONS;
    static {
        RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
        COMMON_OPTIONS = builder.build();
    }

    /**
     * 连接es
     * @return
     */
    @Bean
    public RestHighLevelClient esRestClient() {
        RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(
                new HttpHost("192.168.205.128", 9200, "http")
            )
        );
        return client;
    }
}
存储数据
/**
 * 测试存储数据
 */
@Test
public void indexData() throws IOException {
    // 新建保存请求
    IndexRequest indexRequest = new IndexRequest("users");
    // 若不指定id将自动生成 自动生成的id为一串字符串
    indexRequest.id("1");
    User user = new User();
    user.setAge(23);
    user.setGender("M");
    user.setUserName("zhansan");
    String jsonString = JSON.toJSONString(user);
    // 要保存的jsonString
    indexRequest.source(jsonString, XContentType.JSON);
    // 执行操作
    IndexResponse index = client.index(indexRequest, ElasticsearchConfig.COMMON_OPTIONS);
    System.out.println(index);
}
检索数据
@Test
public void searchData() throws IOException {
    // 创建检索请求
    SearchRequest searchRequest = new SearchRequest();
    // 指定索引
    searchRequest.indices("bank");
    // 指定DSL,检索条件
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    // 构造检索条件
    sourceBuilder.query(QueryBuilders.matchQuery("address", "mill"));
    // 按照年龄聚合
    TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age").size(10);
    sourceBuilder.aggregation(ageAgg);
    // 计算平均薪资
    AvgAggregationBuilder balanceAvg = AggregationBuilders.avg("balanceAvg").field("balance");
    sourceBuilder.aggregation(balanceAvg);
    // 打印检索条件
    System.out.println(sourceBuilder.toString());
    searchRequest.source(sourceBuilder);
    // 执行检索获取响应
    SearchResponse searchResponse = client.search(searchRequest, ElasticsearchConfig.COMMON_OPTIONS);
    // 分析检索结果
    System.out.println(searchResponse.toString());
    // 获取所有查到的数据
    SearchHits hits = searchResponse.getHits();
    SearchHit[] searchHits = hits.getHits();
    for (SearchHit hit : searchHits) {
        String id = hit.getId();
        // ------

        // 将数据转成对象并打印
        String string = hit.getSourceAsString();
        User user = JSON.parseObject(string, User.class);
        System.out.println("user:" + user);
    }
    // 获取聚合信息
    Aggregations aggregations = searchResponse.getAggregations();
    Terms ageAgg1 = aggregations.get("ageAgg");
    for (Terms.Bucket bucket : ageAgg1.getBuckets()) {
        String keyAsString = bucket.getKeyAsString();
        System.out.println("年龄:" + keyAsString);
    }
    Avg balanceAvg1 = aggregations.get("balanceAvg");
    System.out.println("平均薪资:" + balanceAvg1.getValue());
}
更新数据
/**
 * 更新数据
 */
@Test
public void testUpdateForObject() throws IOException {
    UpdateRequest request = new UpdateRequest("bank", "1");
    User user = new User();
    user.setUserName("lisi");
    request.doc(JSON.toJSONString(user), XContentType.JSON);
    // 同步执行
    UpdateResponse updateResponse = client.update(request, ElasticsearchConfig.COMMON_OPTIONS);
    // 打印更新结果
    System.out.println(updateResponse.getResult());
}
删除数据
@Test
public void testDelete() throws IOException {
    DeleteRequest request = new DeleteRequest("bank", "1");
    // 同步执行
    DeleteResponse deleteResponse = client.delete(request, ElasticsearchConfig.COMMON_OPTIONS);
    // 打印删除结果
    System.out.println(deleteResponse.getResult());
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值