ElasticSearch(二)


1. ES继承SpringBoot

自学一门技术首先去官方文档找资料。

ES客户端官网

一般使用高级客户端的文档:7.6的文档传送门

1.1 获取ESmaven依赖
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.6.2</version>
</dependency>
1.2 构建对象

SpringBoot的ES说明

1.3 搭建项目

创建一个空项目将Es项目相关的操作放在该目录下

新建模块,建立一个springboot项目

选中默认模块

创建项目

选中web模块

选中web项目

选中Elastcisearch模块

添加ES相当于非关系数据库

项目环境配置:空项目需要设置自己的编译环境1.8,jdk8,项目的javascript改为ECMAScript6

版本问题不一致时的解决,在pom文件中自定义版本

  <properties>
        <java.version>1.8</java.version>
        <!--如果ES版本依赖过低,需要保证与自己本地下载的版本一致-->
        <!--<elasticsearch.version>7.6.2</elasticsearch.version>-->
    </properties>

查看ES核心类

1.4 查看类中的方法

核心类:

三个静态内部类

上面的三个类都是静态的内部类,ES7.6.1中是RestClientConfigurations类中,个人使用的ES7.6.2,以上的三个类在ElasticsearchRestClientConfigurations类中

class ElasticsearchRestClientConfigurations {
    ElasticsearchRestClientConfigurations() {
    }

    private static class PropertiesCredentialsProvider extends BasicCredentialsProvider {
        PropertiesCredentialsProvider(ElasticsearchRestClientProperties properties) {
            if (StringUtils.hasText(properties.getUsername())) {
                Credentials credentials = new UsernamePasswordCredentials(properties.getUsername(), properties.getPassword());
                this.setCredentials(AuthScope.ANY, credentials);
            }

            properties.getUris().stream().map(this::toUri).filter(this::hasUserInfo).forEach(this::addUserInfoCredentials);
        }

        private URI toUri(String uri) {
            try {
                return URI.create(uri);
            } catch (IllegalArgumentException var3) {
                return null;
            }
        }

        private boolean hasUserInfo(URI uri) {
            return uri != null && StringUtils.hasLength(uri.getUserInfo());
        }

        private void addUserInfoCredentials(URI uri) {
            AuthScope authScope = new AuthScope(uri.getHost(), uri.getPort());
            Credentials credentials = this.createUserInfoCredentials(uri.getUserInfo());
            this.setCredentials(authScope, credentials);
        }

        private Credentials createUserInfoCredentials(String userInfo) {
            int delimiter = userInfo.indexOf(":");
            if (delimiter == -1) {
                return new UsernamePasswordCredentials(userInfo, (String)null);
            } else {
                String username = userInfo.substring(0, delimiter);
                String password = userInfo.substring(delimiter + 1);
                return new UsernamePasswordCredentials(username, password);
            }
        }
    }
    //默认的Rest客户端
    static class DefaultRestClientBuilderCustomizer implements RestClientBuilderCustomizer {
        private static final PropertyMapper map = PropertyMapper.get();
        private final ElasticsearchRestClientProperties properties;

        DefaultRestClientBuilderCustomizer(ElasticsearchRestClientProperties properties) {
            this.properties = properties;
        }

        public void customize(RestClientBuilder builder) {
        }

        public void customize(HttpAsyncClientBuilder builder) {
            builder.setDefaultCredentialsProvider(new ElasticsearchRestClientConfigurations.PropertiesCredentialsProvider(this.properties));
        }

        public void customize(Builder builder) {
            PropertyMapper var10000 = map;
            ElasticsearchRestClientProperties var10001 = this.properties;
            this.properties.getClass();
            var10000.from(var10001::getConnectionTimeout).whenNonNull().asInt(Duration::toMillis).to(builder::setConnectTimeout);
            var10000 = map;
            var10001 = this.properties;
            this.properties.getClass();
            var10000.from(var10001::getReadTimeout).whenNonNull().asInt(Duration::toMillis).to(builder::setSocketTimeout);
        }
    }

    @Configuration(
        proxyBeanMethods = false
    )
    //失败回调静态内部类
    static class RestClientFallbackConfiguration {
        RestClientFallbackConfiguration() {
        }

        @Bean
        @ConditionalOnMissingBean
        RestClient elasticsearchRestClient(RestClientBuilder builder) {
            return builder.build();
        }
    }

    @Configuration(
        proxyBeanMethods = false
    )
    //Rest高水平的客户端配置
    @ConditionalOnClass({RestHighLevelClient.class})
    static class RestHighLevelClientConfiguration {
        RestHighLevelClientConfiguration() {
        }

        @Bean
        @ConditionalOnMissingBean
        RestHighLevelClient elasticsearchRestHighLevelClient(RestClientBuilder restClientBuilder) {
            return new RestHighLevelClient(restClientBuilder);
        }

        @Bean
        @ConditionalOnMissingBean
        RestClient elasticsearchRestClient(RestClientBuilder builder, ObjectProvider<RestHighLevelClient> restHighLevelClient) {
            RestHighLevelClient client = (RestHighLevelClient)restHighLevelClient.getIfUnique();
            return client != null ? client.getLowLevelClient() : builder.build();
        }
    }


    //Rest构建的配置文件,配置端口、连接时间、超时时间等信息
    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnMissingBean({RestClientBuilder.class})
    static class RestClientBuilderConfiguration {
        RestClientBuilderConfiguration() {
        }

        @Bean
        RestClientBuilderCustomizer defaultRestClientBuilderCustomizer(ElasticsearchRestClientProperties properties) {
            return new ElasticsearchRestClientConfigurations.DefaultRestClientBuilderCustomizer(properties);
        }

        @Bean
        RestClientBuilder elasticsearchRestClientBuilder(ElasticsearchRestClientProperties properties, ObjectProvider<RestClientBuilderCustomizer> builderCustomizers) {
            HttpHost[] hosts = (HttpHost[])properties.getUris().stream().map(this::createHttpHost).toArray((x$0) -> {
                return new HttpHost[x$0];
            });
            RestClientBuilder builder = RestClient.builder(hosts);
            builder.setHttpClientConfigCallback((httpClientBuilder) -> {
                builderCustomizers.orderedStream().forEach((customizer) -> {
                    customizer.customize(httpClientBuilder);
                });
                return httpClientBuilder;
            });
            builder.setRequestConfigCallback((requestConfigBuilder) -> {
                builderCustomizers.orderedStream().forEach((customizer) -> {
                    customizer.customize(requestConfigBuilder);
                });
                return requestConfigBuilder;
            });
            builderCustomizers.orderedStream().forEach((customizer) -> {
                customizer.customize(builder);
            });
            return builder;
        }

        private HttpHost createHttpHost(String uri) {
            try {
                return this.createHttpHost(URI.create(uri));
            } catch (IllegalArgumentException var3) {
                return HttpHost.create(uri);
            }
        }

        private HttpHost createHttpHost(URI uri) {
            if (!StringUtils.hasLength(uri.getUserInfo())) {
                return HttpHost.create(uri.toString());
            } else {
                try {
                    return HttpHost.create((new URI(uri.getScheme(), (String)null, uri.getHost(), uri.getPort(), uri.getPath(), uri.getQuery(), uri.getFragment())).toString());
                } catch (URISyntaxException var3) {
                    throw new IllegalStateException(var3);
                }
            }
        }
    }
}

测试类中,可以使用Autowired注入,类名方法名需要一致

//方式一:类名+方法名匹配 
@Autowired
 private RestHighLevelClient restHighLevelClient;
//或者,自定义变量名称
 @Autowired
    @Qualifier("restHighLevelClient")
    private RestHighLevelClient client;
1.5 使用java操作索引
@SpringBootTest
public class StudyesApiApplicationTests {
    //autowried需要指定类型以及相关的方法
    /*spring系列的配置类命名一般都是一下格式:
        XXXAutoConfigration  xxxProperties
    */
    @Autowired
    @Qualifier("restHighLevelClient")
    private RestHighLevelClient client;

    //测试索引的创建  需要有REST请求 request请求
    @Test
    void testCreateIndex() throws IOException {
        //创建索引请求
        CreateIndexRequest request = new CreateIndexRequest("itxing_index");
        //执行创建请求
        CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
        System.out.println(createIndexResponse);
    }

     //测试获取索引,只能够判断索引是否存在
    @Test
    void testExistIndex()throws IOException{
        //指定需要获取的索引
        GetIndexRequest getIndex = new GetIndexRequest("itxing_index");
        boolean exists = client.indices().exists(getIndex, RequestOptions.DEFAULT);
        System.out.println(exists);
    }

    //测试删除索引
    @Test
    void testDeleteIndex()throws IOException{
        DeleteIndexRequest delete = new DeleteIndexRequest("itxing_index");
        AcknowledgedResponse delete1 = client.indices().delete(delete, RequestOptions.DEFAULT);
        //得到删除对象,打印删除对象的isAcknowledged的结果,为true表示删除成功
        System.out.println(delete1.isAcknowledged());
    }
}
1.6 使用java操作文档

创建实体类对象

@Component
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;
    private int age;
}

文档的增、删、改、查以及批量插入操作操作

    //添加文档
    @Test
    void testCreateDoc()throws IOException{
        //1.创建对象
        User user = new User("itxing",25);
        //2.创建请求
        IndexRequest request = new IndexRequest("itxing_index");
        //3.设置规则  PUT /itxing_index/_doc/1
        request.id("1");
        request.timeout(TimeValue.timeValueSeconds(1));
        request.timeout("1s");

        //4.放置请求的数据
        request.source(JSON.toJSONString(user), XContentType.JSON);

        //5.客户端发送请求
        IndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT);
        System.out.println(indexResponse.toString());
        System.out.println(indexResponse.status());//返回命令的状态,第一次为created
    }

    //获取文档  GET /index/doc/1
    @Test
    void testIsExist()throws IOException{
        GetRequest getRequest = new GetRequest("itxing_index", "1");
        //获取返回的_source的上下文
        getRequest.fetchSourceContext(new FetchSourceContext(false));
        getRequest.storedFields("_none_");

        boolean exists = client.exists(getRequest, RequestOptions.DEFAULT);
        System.out.println(exists);
    }

    //获取文档的信息
    @Test
    void testDocInfo()throws IOException{
        GetRequest getRequest = new GetRequest("itxing_index", "1");
        GetResponse response = client.get(getRequest, RequestOptions.DEFAULT);
        System.out.println(response.getSourceAsString());//获取的文档内容
        System.out.println(response);//返回的全部内容和命令是一样的
    }

    //更新文档信息,Post /index/_doc/id/_update
    @Test
    void updateDoc()throws IOException{
        UpdateRequest request = new UpdateRequest("itxing_index","1");
        request.timeout("1s");
        User user = new User("星仔", 23);
        request.doc(JSON.toJSONString(user),XContentType.JSON);
        UpdateResponse update = client.update(request, RequestOptions.DEFAULT);
        System.out.println(update);
        System.out.println(update.status());//返回更新的状态  成功返回OK
    }

    //删除文档
    @Test
    void deleteDoc()throws IOException{
        DeleteRequest request = new DeleteRequest("itxing_index", "1");
        request.timeout("1s");
        DeleteResponse delete = client.delete(request, RequestOptions.DEFAULT);
        System.out.println(delete.status());//返回删除的结果状态  成功返回OK
    }

    //批量查询、插入
    @Test
    void testBulkRequest()throws IOException{
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("10s");
        List<User> list = new ArrayList<>();
        list.add(new User("张三",21));
        list.add(new User("李四",22));
        list.add(new User("张三2",25));
        list.add(new User("王五",26));
        list.add(new User("李二狗",29));

        for(int i=0;i<list.size();i++){
            //批量插入操作
            bulkRequest.add(new IndexRequest(
                    "itxing_index").id(""+(i+1))
                    .source(JSON.toJSONString(list.get(i)),XContentType.JSON));
        }

        BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        System.out.println(bulk.hasFailures());//判断结果是否失败,false 代表成功;true代表成功
    }

 //查询操作
    /*
    * SearchRequest 搜索请求
    * SearchSourceBuilder 条件构造
    * HighlightBuilder构建高亮
    * TermQueryBuilder精确查询
    * MatchAllQueryBuilder 全部匹配查询
    * */
    @Test
    void testSearch()throws IOException{
        SearchRequest searchRequest = new SearchRequest("itxing_index");
        //构建搜索条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //term精确匹配
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "张三");
        //匹配全部查询
//        MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
        sourceBuilder.query(termQueryBuilder);
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        //构建分页,起始页,每页展示的条数
//        sourceBuilder.from();
//        sourceBuilder.size()

        searchRequest.source(sourceBuilder);
        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
        System.out.println(JSON.toJSONString(search.getHits()));
        System.out.println("===========================");
        for(SearchHit document:search.getHits().getHits()){
            System.out.println(document.getSourceAsMap());
        }

    }

2. 项目实战

2.1 爬虫

从jd的网站获取自己想要的数据,最后将其创建索引放在自己的ES中,最后可以进行搜索,爬虫使用的是jsoup类。

<!--jsoup解析网页-->
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.13.1</version>
        </dependency>

爬去的页面主要是搜索的页面jd搜索页面

使用F12可以查看元素中的信息

查看京东官网的页面元素

创建一个Content对象

/**
 * @author xing
 * @create 2020/7/19-studyes
 * 创建一个爬取内容的对象
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Content {
    private String title;
    private String img;
    private String price;
}

将其中的图片的地址信息、价格以及书名爬取下来。

/**
 * @author xing
 * @create 2020/7/19-studyes
 */
public class HtmlParseUtil {
    public static void main(String[] args) throws Exception {
        new HtmlParseUtil().parseJD("java").forEach(System.out::println);
    }

    public List<Content> parseJD(String keyWords)throws Exception{
        //连接网络,获取请求  不能获取ajax
        String url = "https://search.jd.com/Search?keyword="+keyWords+"&enc=utf-8";
        //解析网页
        Document document = Jsoup.parse(new URL(url),30000);
        //所有js中的方法都能够获取,J_goodsList该参数是京东页面的商品信息的顶级div元素
        Element element = document.getElementById("J_goodsList");
        //System.out.println(element.html());
        //获取所有的li元素
        Elements li = element.getElementsByTag("li");
        //遍历所有的li标签
        //大部分的网站将资源延迟加载
        List<Content> list = new ArrayList<>();
        for(Element el:li){
            //获取商品图片的路径、价格、商品名
            String img = el.getElementsByTag("img").eq(0).attr("src");
            String price = el.getElementsByClass("p-price").eq(0).text();
            String title = el.getElementsByClass("p-name").eq(0).text();
            if(img!=""&&price!=""&&title!=""){
                Content content = new Content();
                content.setImg(img);
                content.setPrice(price);
                content.setTitle(title);
                list.add(content);
            }
        }
        return list;
    }
}
2.2 前后端分离

前端使用vue,首先创建vue的项目导入vue的相关js库,创建一个空文件夹,cmd进入命令行,输入以下命令:

npm install vue #前端框架

npm install axios # 这个是前后端通信的

将创建的vue项目中的两个js文件放置在当前的springboot项目下使用,具体的springboot-ES仿jd项目完整版程序放置在gitee上,适用于新手练习使用。

前端的课程依旧推荐狂神说java系列的课程。

vue学习视频

2.3高亮显示

高亮显示设置在于使用HighlightBuilder类对参数进行拼接、对高亮的结果进行解析,前端使用vue将前端信息嵌入,项目中的service文件中对不设置高亮以及设置高亮使用了两个方法(searchPage和searchPageHighLight)

后期的学习:Es的集群学习、ES大数据学习、ES的docker环境搭建

小结

从2020年疫情期间遇到狂神,再也没有办法听别的老师的课程了,秦老师讲的是真的好,作为一个技术新人,如何在该行业走的久、走得远是一个值得思考的问题,对于高校的老师们真的很无语,要么就是研究所谓的人生哲学、有的就是金钱、有的就是职称,这个社会我们还是没有发言的权力,自己还是要努力,才能看起来没那么费力,一起努力!!!


文章作者: it星
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 it星 !
 上一篇
动态规划 动态规划
it星
动态规划题目特点 1.计数的问题 有多少种方式走到右下角 有多少种方法选出k个数使得和是Sum 2.求最大值最小值 从左上角走到右下角路径的最大数字和 最长上升子序列长度 3.求存在性 取石子游戏,先手是否必胜 能不能选出k个数使
2020-07-22
下一篇 
ElasticSearch(一) ElasticSearch(一)
ElasticSearch狂神说ElasticSearch 大数据的时代发展 ElasticSearch是基于Lucene的一个封装的,Lunece是一个用于文本搜索的函数库,其目标是为各种小型应用软件加入全文检索功能。(作者Doug C
2020-07-18
  目录