Java全文搜索引擎—Solr

全文檢索

倒排索引

根據文檔建立索引,再對索引進行查詢獲取文檔。java

相比與順序查詢:不須要那麼多的查詢(一個文檔一個文檔找索引,找到就匹配,須要所有查詢,效率很低),並且能夠在索引上定位,出如今哪一個文檔哪一個地方,支持高亮

Lucene

Lucene是一個基於Java的全文檢索庫,能夠當作一個持久層框架,與Lucene索引交互mysql

倒排索引存儲信息

左邊保存的是一系列字符串,稱爲詞典web

每一個字符串都指向包含此字符串的文檔(Document)鏈表(每一個節點還包含文檔中出現該索引的頻率),此文檔鏈表稱爲倒排表(Posting List)。spring

若是咱們須要查詢包含兩個索引的文檔,只須要將兩個文檔共有的文檔標號鏈接成鏈表

索引建立

  • 對文檔進行分詞,使用Tokenizer ,獲得詞元
分詞器通常使用訓練的模型, WordIK
  1. 去除標點
  2. 去除停用詞(我、是)
  • 還須要把詞元傳遞給語言處理器組件處理

英文:複數->單數,大寫->小寫sql

  • 若索引庫存在相同索引,須要合併成一個鏈表

索引查詢

  • 輸入查詢關鍵字詞
keyword:Java
  • 進行語法分析獲得一棵語法分析樹

  • 搜索索引庫,獲得符合的文檔以及索引的信息
  • 獲得文檔後,根據頻率,相關性排序,分數越高的排在越前面

過程

1. 索引過程:數據庫

1) 有一系列被索引文件apache

2) 被索引文件通過語法分析和語言處理造成一系列詞(Term)segmentfault

3) 通過索引建立造成詞典和反向索引表。緩存

4) 經過索引存儲將索引寫入硬盤。app

2. 搜索過程:

a) 用戶輸入查詢語句。

b) 對查詢語句通過語法分析和語言分析獲得一系列詞(Term)

c) 經過語法分析獲得一個查詢樹。

d) 經過索引存儲將索引讀入到內存。

e) 利用查詢樹搜索索引,從而獲得每一個詞(Term)的文檔鏈表,對文檔鏈表進行交,差,並獲得結果文檔。

f) 將搜索到的結果文檔對查詢的相關性進行排序。

g) 返回查詢結果給用戶。

Solr

Solr是Lucene的封裝,提供分佈式索引,負載均衡查詢,配置式使用,基本只支持Java

  • 安裝:官網
  • API:SolrJ、SpringBoot中的SolrClient
  • core:至關於一張數據庫的表
  • 建立core:solr create -c 「name」
  • web客戶端:http://localhost:8983/solr
  • core目錄:solr-8.2.0/server/solr下

配置

  • managed-schema

在其中配置core的field字段、分詞器等

name:數據庫字段,type:類型,indexed:是否索引,stored:是否緩存,required:是否必須,multiValued:是否多值
<!-- ik分詞器 -->
    <fieldType name="text_ik" class="solr.TextField">
      <analyzer type="index">
          <tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="false" conf="ik.conf"/>
          <filter class="solr.LowerCaseFilterFactory"/>
      </analyzer>
      <analyzer type="query">
          <tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="true" conf="ik.conf"/>
          <filter class="solr.LowerCaseFilterFactory"/>
      </analyzer>
    </fieldType>

    
    <!-- 數據庫字段 -->
    <field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
    <field name="shoes_name" type="text_ik" indexed="true" stored="true" multiValued="false"/>
    <field name="price" type="string" indexed="false" stored="true" multiValued="false"/>
    <field name="details" type="text_ik" indexed="true" stored="true" multiValued="false"/>
    <field name="url" type="string" indexed="false" stored="true" multiValued="false"/>
    <field name="pic_url" type="string" indexed="false" stored="true" multiValued="false"/>
  • solrconfig.xml

當你須要使用web客戶端dataimport時,須要添加:

<requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">
      <lst name="defaults">
        <str name="config">data-config.xml</str>
      </lst>
    </requestHandler>
  • 在統計目錄下建立一個data-config.xml,創建數據庫字段和core field映射
<dataConfig>
    <dataSource type="JdbcDataSource" driver="com.mysql.cj.jdbc.Driver" url="jdbc:mysql://127.0.0.1:3306/priceCompare_goods" user="dzou" password="1234"/>
    <document>
       <entity name="adidas_goods" transformer="DateFormatTransformer" query="SELECT id,shoes_name,details,pic_url,price,url,store_name,comment,shoes_kind FROM adidas_goods">
          <field column="id" name="id"/>
          <field column="shoes_name" name="shoes_name"/>
          <field column="price" name="price"/>
          <field column="details" name="details"/>
          <field column="url" name="url"/>
          <field column="pic_url" name="pic_url"/>
          <field column="shoes_kind" name="shoes_kind"/>
          <field column="store_name" name="store_name"/>
          <field column="score" name="score">
        </entity>
        
    </document>
</dataConfig>

SolrClient API調用

  • 依賴
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-solr</artifactId>
        </dependency>
  • 添加記錄到core
@RequestMapping("/add")
    public String add() throws IOException, SolrServerException {
        SolrInputDocument doc = new SolrInputDocument();
        doc.setField();
        doc.setField();
        doc.setField();
        solrClient.add("",doc);
        solrClient.commit("");
        return "";
    }
  • 刪除core記錄
@RequestMapping("/delete")
    public String delete(String id) throws IOException, SolrServerException {
        solrClient.deleteById(id);
        solrClient.commit("");
        return "";
    }
    
/**
     * 刪除全部的索引
     * @return
     */
    @RequestMapping("deleteAll")
    public String deleteAll(){
        try {

            solrClient.deleteByQuery("","*:*");
            solrClient.commit("");

            return "success";
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "error";
    }
  • 更新記錄
Map<String, String> map = new HashMap<>();
map.put("set", o.getScore());
SolrInputDocument doc = new SolrInputDocument();
doc.addField("id", o.getId());
doc.addField("score", map);
solrClient.add("am_goods", doc);
solrClient.commit("am_goods");
  • 查詢記錄
/**
     * 根據id查詢索引
     * @return
     * @throws Exception
     */
    @RequestMapping("getById")
    public String getById() throws Exception {
        SolrDocument document = solrClient.getById("collection1", "536563");
        System.out.println(document);
        return document.toString();
    }

    /**
     * 綜合查詢: 在綜合查詢中, 有按條件查詢, 條件過濾, 排序, 分頁, 高亮顯示, 獲取部分域信息
     * @return
     */
    @RequestMapping("search/{keyword}")
    public String search(@PathVariable("keyword")String keyword){

        try {
            SolrQuery params = new SolrQuery();
            //查詢條件, 這裏的 q 對應 下面圖片標紅的地方
            params.set("q", "shoes_name:"+keyword);
            //過濾條件
            //params.set("fq", "product_price:[100 TO 100000]");
            //排序
            params.addSort("price", SolrQuery.ORDER.asc);
            //分頁
            params.setStart(0);
            params.setRows(20);
            //默認域
            params.set("df", "shoes_name");
            //只查詢指定域
            //params.set("fl", "id,shoes_name,shoes_kind,shop_name");
            //高亮
            //打開開關
            params.setHighlight(true);
            //指定高亮域
            params.addHighlightField("shoes_name");
            //設置前綴
            params.setHighlightSimplePre("<span style='color:red'>");
            //設置後綴
            params.setHighlightSimplePost("</span>");
            QueryResponse queryResponse = solrClient.query(params);
            /*SolrDocumentList results = queryResponse.getResults();
            results.forEach(System.out::println);*/
            List<HupuGoods> s = queryResponse.getBeans(HupuGoods.class);
            return s.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

ES和Solr區別

  • Solr是配置式,ES是基於RestFul的
  • ES除了搜索還能夠處理分析查詢
  • Solr更面向文本搜索,對於已有數據的查詢Solr更快
  • ES更輕量,發展很快,使用量已經超越Solr
相關文章
相關標籤/搜索