ElasticSearch 和kibana 搭建和api介绍

166 阅读6分钟

ElasticSearch 的版本选择

提要:我是m1的芯片有些版本是不支持的,又考虑springboot支持的elasticsearch版本是7的版本,所以选择了7.1.3版本,这个版本基本上可以直接启动也不用过多的配置,对于新手,或者复习来说搭建难度还是比较小的,我算是踩了一堆坑吧,反正不要选择最新的版本就好了,虽然可以直接启动但是对于只想了解api的使用来说的话没必要。

对了mac用户最好别用brew下载docker 初级选手容易找不到开启的位置,可以直接去官网下载可视版本,虽然最后还是需要命令行来进行操作,但是会给一个很壮观的感受

下载地址:Past Releases of Elastic Stack Software | Elastic

ElasticSearch 和kibana 的搭建

方式1:直接载下来,然后运行 这里直接是启动不来的,需要添加一个启动参数,我贴出来-其实主要就是 discovery.type=single-node 设置一下节点信息,不然的话会有启动的问题

方式2:使用docker pull下来 命令docker pull elasticsearch:7.1.3

docker命令:docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -e "discovery.type=single-node" -d -p 9200:9200 -p 9300:9300 --name ES01 e082d8ac7e5e

ElasticSearch的Maven版本选择

  • 没有标明版本号均采用springboot版本号进行管理

1: spring-boot-starter-parent 2.4.9

2:spring-boot-starter-data-elasticsearch

3:lombok

4:spring-boot-starter-test

5:fastjson 1.2.80

Kibana

基础知识介绍: 索引:可以理解为一个库,就是叫索引库

类型:可以理解为为一个库里面的一张表(elastic7 被删除了全文只有一个_doc)

文档:可以理解为一行一行的数据

字段:可以理解为一列

1:如何创建一个索引

请求方式: 创建一个索引并且同时做一些映射 ~ 对于字段

PUT /dpyuyutest
{
  "mappings": {
    "properties": {
      "title":{
        "type": "keyword"
      },
      "name":{
        "type": "text"
      }
    }
  },
  "settings": {
    "number_of_replicas": 5, 
    "number_of_shards": 1
  }
}

返回参数:

{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "dpyuyutest"
}

number_of_replicas:副本数量 number_of_shards:分片数量

2:查询一个索引

请求方式:

GET /dpyuyutest

响应参数:

{
  "dpyuyutest" : {
    "aliases" : { },
    "mappings" : {
      "properties" : {
        "name" : {
          "type" : "text"
        },
        "title" : {
          "type" : "keyword"
        }
      }
    },
    "settings" : {
      "index" : {
        "routing" : {
          "allocation" : {
            "include" : {
              "_tier_preference" : "data_content"
            }
          }
        },
        "number_of_shards" : "1",
        "provided_name" : "dpyuyutest",
        "creation_date" : "1654445455453",
        "number_of_replicas" : "5",
        "uuid" : "UzkJB6SFQYW1pCLjfUWDvQ",
        "version" : {
          "created" : "7160299"
        }
      }
    }
  }
}

这里也是正常显示了一些mappings和settings 的设置

3:删除索引

请求方式 :

DELETE /dpyuyutest

返回参数:

{
  "acknowledged" : true
}

4:添加文档

请求方式 :

POST /dpyuyutest/_doc
{
  "title":"我是二号标题",
  "name":"bmw"
}

返回参数:

{
  "_index" : "dpyuyutest",
  "_type" : "_doc",
  "_id" : "vuquNIEBJMhLMVgDlISa",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 6,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 1,
  "_primary_term" : 1
}

注意:这里需要注意的是,_doc是elasticsearch7之后全文唯一类型,所以添加的时候需要写上不写上的会报错。

5:查询指定索引全部文档

请求方式 :

GET dpyuyutest/_search
{
  "query": {
    "match_all": {}
  }
}

返回参数:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "dpyuyutest",
        "_type" : "_doc",
        "_id" : "veqtNIEBJMhLMVgDooRm",
        "_score" : 1.0,
        "_source" : {
          "title" : "我是一号标题",
          "name" : "bmw"
        }
      },
      {
        "_index" : "dpyuyutest",
        "_type" : "_doc",
        "_id" : "vuquNIEBJMhLMVgDlISa",
        "_score" : 1.0,
        "_source" : {
          "title" : "我是二号标题",
          "name" : "bmw"
        }
      }
    ]
  }
}

hits:里面是我添加进去的两个文档。

6:文档删除

请求方式 :

DELETE /dpyuyutest/_doc/veqtNIEBJMhLMVgDooRm 

返回参数:

{
  "_index" : "dpyuyutest",
  "_type" : "_doc",
  "_id" : "veqtNIEBJMhLMVgDooRm",
  "_version" : 2,
  "result" : "deleted",
  "_shards" : {
    "total" : 6,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 2,
  "_primary_term" : 1
}

DELETE /索引/唯一类型/id

7:match查询(分词查询)

请求方式 :

GET /dpyuyutest/_search
{
  "query": {
    "match": {
      "name": "bmw"
    }
  }
}

//还可以这样写,制定查询精度
GET /dpyuyutest/_search
{
  "query": {
    "match": {
      "type":{
        "query": "b",
        "minimum_should_match": "75%" //是指最少匹配百分比
      }
    }
  }
}

返回参数:

{
  "took" : 5,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "dpyuyutest",
        "_type" : "_doc",
        "_id" : "vuquNIEBJMhLMVgDlISa",
        "_score" : 0.2876821,
        "_source" : {
          "title" : "我是二号标题",
          "name" : "bmw"
        }
      }
    ]
  }
}

8:term查询(完全匹配,不分词)

请求方式 :

GET /dpyuyutest/_search
{
  "query": {
    "term": {
      "name": "bmw"
    }
  }
}

返回参数:

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "dpyuyutest",
        "_type" : "_doc",
        "_id" : "vuquNIEBJMhLMVgDlISa",
        "_score" : 0.2876821,
        "_source" : {
          "title" : "我是二号标题",
          "name" : "bmw"
        }
      }
    ]
  }
}

9:boolean 查询 (与或非)

请求方式 :

GET /dpyuyutest/_search
{
  "query": {
   "bool": {
     "must": [
       {"term": {"name": {"value": "bmw"}}}
       ],
      "should": [
        {"match": {
          "title": "我们是二号标题"
        }}
      ],
      "must_not": [
        {"match": {"title": "54"}}
      ]
   }
  }
}

返回参数:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.276251,
    "hits" : [
      {
        "_index" : "dpyuyutest",
        "_type" : "_doc",
        "_id" : "v-rBNIEBJMhLMVgD4oTh",
        "_score" : 1.276251,
        "_source" : {
          "title" : "我是二号标题",
          "name" : "bmw"
        }
      },
      {
        "_index" : "dpyuyutest",
        "_type" : "_doc",
        "_id" : "wOrCNIEBJMhLMVgD64Rt",
        "_score" : 1.276251,
        "_source" : {
          "title" : "我是二号标题",
          "name" : "bmw"
        }
      }
    ]
  }
}

must(与) 子句必须出现在匹配的文档中,并将对分数起作用

must_not(非) 子句不得出现在匹配的文档中。

shuold (或) 子句应出现在匹配文档中。

10:简单的聚合查询

请求参数

GET /dpyuyutest/_search
{
  "aggs": {
    "agg_title": {
      "terms": {
        "field": "title.keyword",
        "size": 10
      }
    }
  }
}

返回参数:

{
  "took" : 10,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "dpyuyutest",
        "_type" : "_doc",
        "_id" : "v-rBNIEBJMhLMVgD4oTh",
        "_score" : 1.0,
        "_source" : {
          "title" : "我是二号标题",
          "name" : "bmw"
        }
      },
      {
        "_index" : "dpyuyutest",
        "_type" : "_doc",
        "_id" : "wOrCNIEBJMhLMVgD64Rt",
        "_score" : 1.0,
        "_source" : {
          "title" : "我是二号标题",
          "name" : "bmw"
        }
      }
    ]
  },
  "aggregations" : {
    "agg_title" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "我是二号标题",
          "doc_count" : 2
        }
      ]
    }
  }
}

这个参数 : "field": "title.keyword", 在6版本的时候是不用加keyword参数的; agg_title:这个参数是自定义参数

ElasticSearch 的增删改查

1:配置类

import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration;

/**
 * ElasticSearch 客户端配置
 */
@Configuration
public class RestClientConfig extends AbstractElasticsearchConfiguration {
    @Override
    @Bean
    public RestHighLevelClient elasticsearchClient() {
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("elastic", "********"));  //es账号密码(默认用户名为elastic)
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                                new HttpHost("localhost", 9200, "http"))
                        .setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
                            public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
                                httpClientBuilder.disableAuthCaching();
                                return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                            }
                        }));
        return client;
    }
}

2:crud测试类

@SpringBootTest
public class ElasticTest {

    @Autowired
    public RestHighLevelClient client;

    // 测试索引的创建, Request PUT liuyou_index
    @Test
    public void testCreateIndex() throws IOException {
        CreateIndexRequest request = new CreateIndexRequest("dpyuyutest");
        CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
        //   System.out.println(response);
        System.out.println(response.isAcknowledged());// 查看是否创建成功
        System.out.println(response);// 查看返回对象
        client.close();
    }

    // 测试获取索引,并判断其是否存在
    @Test
    public void testIndexIsExists() throws IOException {
        GetIndexRequest request = new GetIndexRequest("dpyuyutest");
        boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
        System.out.println(exists);// 索引是否存在
        client.close();
    }

    // 索引删除
    @Test
    public void testDeleteIndex() throws IOException {
        DeleteIndexRequest request = new DeleteIndexRequest("dpyuyutest");
        AcknowledgedResponse response = client.indices().delete(request, RequestOptions.DEFAULT);
        System.out.println(response.isAcknowledged());// 是否删除成功
        client.close();
    }

    // 测试添加文档(先创建一个User实体类,添加fastjson依赖)
    @Test
    public void testAddDocument() throws IOException {
        // 创建一个User对象
        Book book = new Book("2","elasticsearch","1",2.0d,new Date(),new Date());
        // 创建请求
        IndexRequest request = new IndexRequest("dpyuyutest");
        // 制定规则 PUT /dpyuyutest/_doc/1
        request.id("1");// 设置文档ID
        request.timeout(TimeValue.timeValueMillis(1000));// request.timeout("1s")
        // 将我们的数据放入请求中
        request.source(JSON.toJSONString(book), XContentType.JSON);
        // 客户端发送请求,获取响应的结果
        IndexResponse response = client.index(request, RequestOptions.DEFAULT);
        System.out.println(response.status());// 获取建立索引的状态信息 CREATED
        System.out.println(response);// 查看返回内容 IndexResponse[index=liuyou_index,type=_doc,id=1,version=1,result=created,seqNo=0,primaryTerm=1,shards={"total":2,"successful":1,"failed":0}]
    }

    // 获取文档,判断是否存在 get /index/_doc/1
    @Test
    void testIsExists() throws IOException {
        GetRequest request = new GetRequest("dpyuyutest", "1");
        // 不获取返回的 _source 的上下文了
        request.fetchSourceContext(new FetchSourceContext(false));
        request.storedFields("_none_");
        boolean exists = client.exists(request, RequestOptions.DEFAULT);
        System.out.println(exists);
    }

    // 测试获得文档信息
    @Test
    public void testGetDocument() throws IOException {
        GetRequest request = new GetRequest("dpyuyutest","1");
        request.storedFields("");
        GetResponse response = client.get(request, RequestOptions.DEFAULT);
        System.out.println(response.getSourceAsString());// 打印文档内容
        System.out.println(request);// 返回的全部内容和命令是一样的
        client.close();
    }

    // 测试更新文档内容
    @Test
    public void testUpdateDocument() throws IOException {
        UpdateRequest request = new UpdateRequest("dpyuyutest", "1");
        Book book = new Book("2","elasticsearch","1",2.0d,new Date(),new Date());
        request.doc(JSON.toJSONString(book),XContentType.JSON);
        UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
        System.out.println(response.status()); // OK
        client.close();
    }

    // 删除文档
    @Test
    public void testDeleteDocument() throws IOException {
        DeleteRequest request = new DeleteRequest("dpyuyutest", "1");
        request.timeout("1s");
        DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);
        System.out.println(response.status());// OK
    }

    // 批量插入数据
    @Test
    public void testBulk() throws IOException {
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("10s");
        ArrayList<Book> users = new ArrayList<>();
        users.add(new Book("2","elasticsearch","1",2.0d,new Date(),new Date()));
        users.add(new Book("3","elasticsearch","1",2.0d,new Date(),new Date()));
        users.add(new Book("4","elasticsearch","1",2.0d,new Date(),new Date()));
        users.add(new Book("5","elasticsearch","1",2.0d,new Date(),new Date()));
        users.add(new Book("6","elasticsearch","1",2.0d,new Date(),new Date()));

        // 批量请求处理
        for (int i = 0; i < users.size(); i++) {
            bulkRequest.add(
                    // 这里是数据信息
                    new IndexRequest("dpyuyutest")
                            .id(""+(i + 1)) // 没有设置id 会自定生成一个随机id
                            .source(JSON.toJSONString(users.get(i)),XContentType.JSON)
            );
        }
        BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        System.out.println(bulk.status());// ok
    }

    // 查询
// SearchRequest 搜索请求
// SearchSourceBuilder 条件构造
// HighlightBuilder 高亮
// TermQueryBuilder 精确查询
// MatchAllQueryBuilder
// xxxQueryBuilder ...
    @Test
    public void testSearch() throws IOException {
        // 1.创建查询请求对象
        SearchRequest searchRequest = new SearchRequest("dpyuyutest");
        // 2.构建搜索条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // (1)查询条件 使用QueryBuilders工具类创建
        // 精确查询
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", "elasticsearch");
        // 匹配查询
        //  MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
        AvgAggregationBuilder title = AggregationBuilders.avg("title");
        // (2)其他<可有可无>:(可以参考 SearchSourceBuilder 的字段部分)
        // 设置高亮
        searchSourceBuilder.highlighter(new HighlightBuilder());
        //        // 分页
        //        searchSourceBuilder.from();
        //        searchSourceBuilder.size();
        searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        // (3)条件投入
        searchSourceBuilder.query(termQueryBuilder);
        // 3.添加条件到请求
        searchRequest.source(searchSourceBuilder);
        // 4.客户端查询请求
        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
        // 5.查看返回结果
        SearchHits hits = search.getHits();
        System.out.println(JSON.toJSONString(hits));
        System.out.println("=======================");
        for (SearchHit documentFields : hits.getHits()) {
            System.out.println(documentFields.getSourceAsMap());
        }
    }
//聚合查询,是可以查询到buckets 可以拿kibana 进行一个聚合查询 
    @Test
    public void Agg() throws IOException {
        //es聚合测试
        //构建bool查询
        SearchRequest searchRequest = new SearchRequest("dpyuyutest");
        TermsAggregationBuilder agg = AggregationBuilders.terms("agg_title").field("title");
       searchRequest.source().aggregation(agg);
        //构建聚合查询
        /*   .subAggregation(AggregationBuilders.stats("res_score").field("score"))
                .subAggregation(AggregationBuilders.histogram("avg_price").field("price").interval(500))*/
        //解析返回值

        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        //取出第一次聚合的terms
        Terms terms = searchResponse.getAggregations().get("agg_title");
        List<? extends Terms.Bucket> buckets = terms.getBuckets();
        Map<String,Object> resultMap = new HashMap<>();
        //在terms的buckets下,取出stats结果
        terms.getBuckets().forEach(item -> {
            System.out.println(item.getKey());
            System.out.println(item.getDocCount());
        });
        System.out.println(resultMap.toString());


    }