Spring Boot + Elasticsearch實現大批量數據集下中文的精確匹配-案例剖析

原因

數據存儲在MYSQ庫中,數據基本維持不變,但數據量又較大(幾千萬)放在MYSQL中查詢效率上較慢,尋求一種簡單有效的方式提升查詢效率,MYSQL並不擅長大規模數據量下的數據查詢。前端

技術方案

考慮後期一樣會使用到es,這次直接結合spring-boot框架造成一個獨立服務,並不涉及UI展示內容,(ES版本2.4.5,5.0+版本的話就不能再使用spring data elasticsearch)技術組合以下:java

Spring Boot+ Spring-data-elasticsearch + Elasticsearchmysql

結合elasticsearch-jdbc插件,全量將數據一次性導入es中,後期不涉及數據變動。git

es安裝

測試期間單機安裝,官網下載對應版本,因爲筆者工做環境基於JDK7,因此下載5.0如下版本,5.0+均依賴Java8,同時使用到elasticsearch-jdbc插件,一併下載安裝完成。程序員

走過的大彎路

直接使用elasticsearch-jdbc工具,編寫腳本文件,抽取數據到es中,腳本樣例以下:github

 
  1. #!/bin/shweb

  2.  

  3. DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"spring

  4. bin=${DIR}/../binsql

  5. lib=${DIR}/../lib緩存

  6.  

  7. echo '

  8. {

  9.    "type": "jdbc",

  10.    "jdbc": {

  11.        "elasticsearch.autodiscover": true,

  12.        "url": "jdbc:mysql://192.168.1.3:3306/test",

  13.        "user": "root",

  14.        "password": "root",

  15.        "sql": "SELECT * from tb_name1",

  16.        "elasticsearch": {

  17.            "host": "192.168.1.1",

  18.            "port": 9300

  19.        },

  20.        "index": "my-index",

  21.        "type": "my-type"

  22.    }

  23. }

  24. ' | java \

  25.    -cp "${lib}/*" \

  26.    -Dlog4j.configurationFile=${bin}/log4j2.xml \

  27.    org.xbib.tools.Runner \

  28.    org.xbib.tools.JDBCImporter

數據導入成功後,可以使用head插件直接查看到。使用基本查詢測試,查詢條件是name=測試&num=100,使用精確匹配term語句,查詢數據未果,實際使用num=100獨立查詢時,有相關數據。

問題跟蹤解決

致使此現象的緣由在於中文分詞的問題,使用elasticsearch-jdbc腳本中並未處理列的mapping類型。(中間作過一次嘗試,在腳本中定義對應的type_mapping,但並未成功,有興趣的朋友可再作嘗試)。

注:es與ik分詞插件結合,版本匹配須要特別關注,但本案例並不涉及

結合此案例,查詢時並不須要分詞,而是精確匹配,但es默認狀況下是指定string類型的分詞,因此在index建立以前咱們須要手動指定相關列不須要分詞:not_analyzed,形如:

 
  1. CURL -XPOST http://192.168.1.105:9200/my-index -d {

  2.  

  3.    {

  4.    "mappings": {

  5.        "my-type": {

  6.            "properties": {

  7.                "name": {

  8.                    "type": "string",

  9.                    "index": "not_analyzed"

  10.                },

  11.                "num": {

  12.                    "type": "string",

  13.                    "index": "not_analyzed"

  14.                }

  15.            }

  16.        }

  17.    }

  18. }

建立索引成功後,再使用elasticsearch-jdbc的腳本導入數據,相關數據列不會再使用分詞分析,再使用term組合精確查詢時,就能夠查詢相關數據來。

SpringBoot應用

pom.xml關鍵配置

 
  1. <dependency>

  2.    <groupId>org.springframework.boot</groupId>

  3.    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>

  4. </dependency>

  5. <dependency>

  6.    <groupId>org.springframework.boot</groupId>

  7.    <artifactId>spring-boot-starter-web</artifactId>

  8.    <exclusions>

  9.        <exclusion>

  10.            <artifactId>log4j-over-slf4j</artifactId>

  11.            <groupId>org.slf4j</groupId>

  12.        </exclusion>

  13.    </exclusions>

  14. </dependency>

  15. <dependency>

  16.    <groupId>org.springframework.boot</groupId>

  17.    <artifactId>spring-boot-starter</artifactId>

  18.    <exclusions>

  19.        <exclusion>

  20.            <groupId>org.springframework.boot</groupId>

  21.            <artifactId>spring-boot-starter-logging</artifactId>

  22.        </exclusion>

  23.    </exclusions>

  24. </dependency>

  25. <dependency>

  26.    <groupId>org.springframework.boot</groupId>

  27.    <artifactId>spring-boot-starter-test</artifactId>

  28.    <scope>test</scope>

  29. </dependency>

  30. <dependency>

  31.    <groupId>org.springframework.boot</groupId>

  32.    <artifactId>spring-boot-starter-log4j</artifactId>

  33.    <version>1.3.1.RELEASE</version>

  34. </dependency>

與elasticsearch交互實體

 
  1. @Data

  2. @Document(indexName = "my-index", type = "my-type", shards = 5, replicas = 1, indexStoreType = "fs", refreshInterval = "-1")

  3. public class DataBean {

  4.  

  5.    /**

  6.     * code:名稱

  7.     *

  8.     * @since JDK 1.6

  9.     */

  10.    public String name;

  11.  

  12.    /**

  13.     * msg:編號

  14.     *

  15.     * @since JDK 1.6

  16.     */

  17.    public String num;

  18.  

  19. }

與es交互接口類,返回數據的惟一_id值,若查得數據表示命中數據,若爲空並未數據不存在

 
  1. public interface DataBeanRepository extends ElasticsearchRepository<DataBean, Long> {

  2.    //案例中並未使用,但能夠用

  3.    public List<BlackGreyData> findByNameAndNum(String name, String num);

  4. }

下面是業務處理層,採用BoolQueryBuilder構建查詢條件,也便可基於DSL模塊查詢數據,還能夠採用Criteria查詢。

 
  1. @Autowired

  2.    DataBeanRepository repository;

  3.  

  4.    @Override

  5.    public List<DataBean> query(String name, String num, String type) {

  6.        //採用過濾器的形式,提升查詢效率

  7.        BoolQueryBuilder builder = QueryBuilders.boolQuery();

  8.        builder.must(QueryBuilders.termQuery("name", name)).must(QueryBuilders.termQuery("num", num));

  9.        Iterable<DataBean> lists = repository.search(builder);

  10.  

  11.        List<DataBean> datas = new ArrayList<>();

  12.        for (DataBean dataBean : lists) {

  13.            datas.add(dataBean);

  14.            logger.info("---------------------->>>Request result = 【" + dataBean + "】");

  15.        }

  16.        return datas;

  17.    }

其它再編寫對應的請求響應邏輯,便可完成簡單服務的完成。

測試結果

GPS數據量5000W+,精確匹配查詢出來50條數據,耗時700ms左右,結果查詢緩存機制,基本能夠穩定在300ms左右。這也是在單節點,未做任何優化的狀況的結果。

源碼地址

https://github.com/backkoms/spring-boot-elasticsearch

擴展閱讀:

歪脖貳點零  ∣ 認知升級· 終身學習

程序員,除了編碼,生活還應該有沉澱!

長按,識別二維碼,加關注

相關文章
相關標籤/搜索