ElasticSearch的简单运用以及枚举实现单例模式

在公司做小店铺的电商项目的时候,自己虽然大部分任务是放在前端,但是也在群里听到他们说清ES的数据,我就在想ES是个什么玩意,然后便去搜索看看。发现ES也就是ElasticSearch。

ElasticSearch是基于 Lucene的搜索服务器,它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful接口。RESTful指的是具有REST风格架构风格的。对于REST:分布式应用架构风格,其实我自己也没有特别理解。在网上看到的说:面向资源是REST最明显的特征,比如HTTP协议就是属于REST架构的设计模式:无状态请求。这里给一个链接可以参考一下这篇文章:

理解本身的REST架构风格

Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。这里说的实时搜索值的是近实时搜索。同时在网络上看到ElasticSearch跟solr进行比较(两种搜索引擎我都没有了解过,这几天才开始尝试)

两种搜索引擎的比较 链接

我这边安转ElasticSearch在Windows跟Linux系统上面都进行过尝试,Windows安装过程挺顺利的,但是Linux安装非常坎坷,昨天折腾一下午,最后还是安转好了(因为是腾讯的学生云主机)内存比较小,所以需要改虚拟机的启动配置不然总是被killed,然后其他的问题遇到就百度,没有进行记录,这里不再赘述了。

下面结合Spring Boot开始使用ElasticSearch。

资源文件:

spring.data.elasticsearch.cluster-name=my-application //这里是你配置文件中设置的名字
spring.data.elasticsearch.cluster-nodes=111.***.**.***:9300 //服务器IP
spring.data.elasticsearch.repositories.enable=true  

server.port=8081 

配置好资源文件之后,就开始使用它了(我这里是要爬取我自己CSDN博客的个人信息去存储到ElasticSearch,并获取)

关于爬取信息在文章末尾也叙述一下,这里还是来说一下Java操作ElasticSearch的过程

首先是Dao层:

package com.elastic.search.dao;

import com.elastic.search.vo.CSDNInfoVO;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Component;

@Component
public interface CsdnDao extends ElasticsearchRepository<CSDNInfoVO, Long> {
    CSDNInfoVO queryById(Long id);
}
@Component:

泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。

关于ElasticsearchRepository这个类看后面这个单词Repository,可以猜测他是一个数据访问的接口

然后是Service层

 public List<CSDNInfoVO> getcsdninfo() {
        List<CSDNInfoVO> list = new ArrayList<>();
        Long num = csdnDao.count();
        for (long i = 1; i <= num; i++) {
            list.add(csdnDao.queryById(i));
        }
        return list;
    } 

这里其实是我自己定时爬虫爬取的数据,并且只有10条,代码如下

    @Scheduled(cron = "0 0 0,13,18,21 * * ?")  
    public void testCron() {
        try {
            CSDNInfoVO csdnInfoVO = csdnHtml.getInfo();
            Long num = csdnDao.count();
            if (num > 9) { //一旦ES中的数据量超过10条,就开始清除第一条数据,保证ES数据为10条不会变
                CSDNInfoVO csdnInfoVO2 = csdnDao.queryById(Long.parseLong("1"));
                csdnDao.delete(csdnInfoVO2);
                for (long i = 2; i < 11; i++) {
                    csdnInfoVO2 = csdnDao.queryById(i);
                    csdnInfoVO2.setId(i - 1);
                    csdnDao.save(csdnInfoVO2);
                }
                num = new Long((long) 9);
            }
            csdnInfoVO.setId(num + 1);
            csdnInfoVO.setCreateTime(new Date());
            csdnDao.save(csdnInfoVO);
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        logger.info("===initialDelay: 第{}次执行方法", csdnDao.count());
    }
} 

控制层(这个是我测试使用的,真正的控制层现在只有一个方法)

@RequestMapping("add")
    public String add(){
        TestVO testVO = new TestVO();
        testVO.setId("2");
        testVO.setName("陈龙");
        testDao.save(testVO);
        return "success";
    }
    @RequestMapping("query")
    public TestVO query(){
        TestVO testVO = testDao.queryTestById("1");
        return testVO;
    }

    //删除
    @RequestMapping("/delete")
    public String delete(){
        TestVO testVO = testDao.queryTestById("1");
        testDao.delete(testVO);
        return "success";
    }

    //局部更新
    @RequestMapping("/update")
    public String update(){

        TestVO employee=testDao.queryTestById("1");
        employee.setName("Elastic Search Test 陈龙");
        testDao.save(employee);

        System.err.println("update a obj");

        return "success";
    }

vo

@Document(indexName = "csdn",type = "info",shards = 1,replicas = 0,refreshInterval = "-1") //这里indexName类似于数据库名注意要小写
public class CSDNInfoVO { //type 类似于表名 下面就是字段了
    @Id
    private Long id;
    @Field
    public String csdnName;
    @Field
    public String csdnImg;
    @Field
    public String csdnArticl;
    @Field
    public String csdnFenSi;
    @Field
    public String csdnLike;
    @Field
    public String csdnComment;
    @Field
    public String csdnGrade;
    @Field
    public String csdnVisitNum;
    @Field
    public String csdnIntegral;
    @Field
    public String csdnRanking;
    @Field
    public Date createTime;   //set get 方法这里不在复制} 

ok,这就是Spring Boot简单结合ElasticSearch。

下面来记录一下爬虫的过程:

首先自己使用的是HTMLunit这个框架,但是它对元素的获取我觉得有点麻烦,于是最后又结合自己熟悉的Jsoup来完成数据的爬取:

package com.elastic.search.htmlunit;

import com.elastic.search.vo.CSDNInfoVO;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.*;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;

@Service
public class CSDNHtml {
    private Logger logger = LoggerFactory.getLogger(CSDNHtml.class);

    public CSDNInfoVO getInfo() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException, IOException {
        CSDNInfoVO csdnInfoVO = new CSDNInfoVO();
        WebClient webClient = WebClientFactory.INSTANCE.getWebClient();
        HtmlPage htmlPage = WebClientFactory.INSTANCE.getHtmlPage();
        webClient.getOptions().setJavaScriptEnabled(false);
        webClient.getOptions().setCssEnabled(false);
        webClient.getOptions().setUseInsecureSSL(true);
//        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
//            public boolean isTrusted(X509Certificate[] chain,
//                                     String authType) throws CertificateException {
//                return true;
//            }
//        }).build();
//        webClient.waitForBackgroundJavaScript(30000);
        HtmlDivision domElement = htmlPage.getHtmlElementById("asideProfile");
        String pageXml = domElement.asXml();
        Document document = Jsoup.parse(pageXml);
//        System.out.println(document.body());
        Elements elements = document.select("img[src]");
        for (Element element : elements) {
            csdnInfoVO.setCsdnImg(element.attr("src"));
        }
        String name = document.getElementById("uid").text();
        Elements elements1 = document.getElementsByTag("dd");
        Elements elements2 = document.getElementsByTag("dl");
        String article = elements1.get(0).text();
        String fensi = elements1.get(1).text();
        String like = elements1.get(2).text();
        String comment = elements1.get(3).text();
        String grade = elements1.get(4).getElementsByTag("a").attr("title");
        String visitNum = elements1.get(5).attr("title");
//        System.out.println(elements1.get(6).attr("title"));
        String csdnIntegral = elements1.get(6).text();
        String rank = elements2.get(7).attr("title");
        csdnInfoVO.setCsdnName(name);
        csdnInfoVO.setCsdnArticl(article);
        csdnInfoVO.setCsdnFenSi(fensi);
        csdnInfoVO.setCsdnLike(like);
        csdnInfoVO.setCsdnComment(comment);
        csdnInfoVO.setCsdnGrade(grade);
        csdnInfoVO.setCsdnVisitNum(visitNum);
        csdnInfoVO.setCsdnIntegral(csdnIntegral);
        csdnInfoVO.setCsdnRanking(rank);
        logger.info(csdnInfoVO.toString());
        return csdnInfoVO;
    }

    public static void main(String[] args) throws IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        CSDNHtml csdnHtml = new CSDNHtml();
//        for (int i=0;i<4;i++){
        csdnHtml.getInfo().toString();
//         }
    }
}

最开始的使用我在方法里面new webClient跟HTMlPage这个对象,但是我想到每次创建这个实例花销太大(自己看到控制台消息跑的飞起,就知道这个实例创建比较费劲),于是就想到单例模式,说到单例模式这里不得不说一下Effective Java这本书,这本书上说推荐使用枚举类型来实现单例模式,在以前我见到的单例模式--懒汉,饿汉,以及网上看到的双重校验锁

public static Singleton getSingleton() {
    if (instance == null) {                         //Single Checked
        synchronized (Singleton.class) {
            if (instance == null) {                 //Double Checked
                instance = new Singleton();
            }
        }
    }
    return instance ;
}

也就是对象加锁,由于使用了单例模式,所以后续的对象创建次数会比较小,在加锁之前进行一次判断。为什么在同步块内还要再检验一次?因为可能会有多个线程一起进入同步块外的 if,如果在同步块内不进行二次检验的话就会生成多个实例了。

我这里使用的是枚举创建单例模式

package com.elastic.search.htmlunit;

import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

public enum  WebClientFactory {
    INSTANCE;
    private Logger logger = LoggerFactory.getLogger(WebClientFactory.class);
    private WebClient webClient=null;
    private HtmlPage htmlPage=null;
    WebClientFactory() {
        logger.info("示例创建");
        webClient = new WebClient();
        try {
            htmlPage = webClient.getPage("https://blog.csdn.net/qq442270636");
        } catch (IOException e) {
            e.printStackTrace();
        }
        logger.info("示例创建結束");
    }
    public HtmlPage getHtmlPage() {

        return htmlPage;
    }

    public WebClient getWebClient() {
        return webClient;
    }
}

走到这里其实已经走完了。看一下效果



猜你喜欢

转载自blog.csdn.net/qq442270636/article/details/80139391
今日推荐