全文搜索引擎Elasticsearch的基本原理及使用

全文搜索引擎的概念

全文搜索引擎是目前廣泛應(yīng)用的主流搜索引擎。它的工作原理是計(jì)算機(jī)索引程序通過(guò)掃描文章中的每一個(gè)詞蚀乔,對(duì)每一個(gè)詞建立一個(gè)索引蒋纬,指明該詞在文章中出現(xiàn)的次數(shù)和位置泊愧,當(dāng)用戶查詢時(shí)村视,檢索程序就根據(jù)事先建立的索引進(jìn)行查找官套,并將查找的結(jié)果反饋給用戶的檢索方式。這個(gè)過(guò)程類似于通過(guò)字典中的檢索字表查字的過(guò)程蚁孔。

常見的全文搜索引擎及對(duì)比

①Lucene

Lucene是一個(gè)Java全文搜索引擎奶赔,完全用Java編寫。Lucene不是一個(gè)完整的應(yīng)用程序杠氢,而是一個(gè)代碼庫(kù)和API站刑,可以很容易地用于向應(yīng)用程序添加搜索功能

優(yōu)點(diǎn):比較成熟的解決方案,具有活躍的社區(qū)鼻百,經(jīng)過(guò)優(yōu)化笛钝,可以支持10億+的搜索
缺點(diǎn):所有的擴(kuò)展质况,分布式,可靠性等都需要自己實(shí)現(xiàn)玻靡;非實(shí)時(shí),從建索引到可以搜索中間有一個(gè)時(shí)間延遲中贝。

②solar

Solr是一個(gè)基于名為L(zhǎng)ucene的Java庫(kù)構(gòu)建的開源搜索平臺(tái)囤捻。它以用戶友好的方式提供Apache Lucene的搜索功能。作為一個(gè)行業(yè)參與者近十年邻寿,它是一個(gè)成熟的產(chǎn)品蝎土,擁有強(qiáng)大而廣泛的用戶社區(qū)。它提供分布式索引绣否,復(fù)制誊涯,負(fù)載平衡查詢以及自動(dòng)故障轉(zhuǎn)移和恢復(fù)。如果它被正確部署然后管理得好蒜撮,它就能夠成為一個(gè)高度可靠暴构,可擴(kuò)展且容錯(cuò)的搜索引擎

優(yōu)點(diǎn):Solr有一個(gè)更大、更成熟的用戶段磨、開發(fā)和貢獻(xiàn)者社區(qū)取逾;支持多種文件的索引,如JSON,XML,CSV,PDF,HTML,WORD苹支;不考慮建立索引砾隅,搜索速度更快。
缺點(diǎn):建立索引耗時(shí)較長(zhǎng)债蜜,實(shí)時(shí)搜索的效率不高

③Elasticsearch

Elasticsearch(elastic)是一個(gè)基于Apache Lucene庫(kù)構(gòu)建的RESTful搜索引擎,它提供了一個(gè)分布式晴埂,多租戶能力的全文搜索引擎,具有HTTP Web界面(REST)和無(wú)架構(gòu)JSON文檔寻定。分布式搜索引擎包括可以劃分為分片的索引儒洛,并且每個(gè)分片可以具有多個(gè)副本。每個(gè)Elasticsearch節(jié)點(diǎn)都可以有一個(gè)或多個(gè)分片特姐,其引擎也可以充當(dāng)協(xié)調(diào)器晶丘,將操作委派給正確的分片。

優(yōu)點(diǎn):Elasticsearch是分布式的唐含,可以實(shí)時(shí)分發(fā)浅浮;支持Lucene接近實(shí)時(shí)的搜索;處理多租戶(multienancy)不需要特殊的配置,而slor則需要更多高級(jí)的配置
缺點(diǎn):社區(qū)沒有solar那么活躍捷枯;由于發(fā)布出來(lái)時(shí)間較短滚秩,較solar不穩(wěn)定;不夠自動(dòng)淮捆,不適應(yīng)當(dāng)前新的index warmup API(索引預(yù)熱)

Elasticsearch基本概念

①Index:索引郁油,Elastic 數(shù)據(jù)管理的頂層單位本股,寫入數(shù)據(jù)后經(jīng)處理會(huì)生成倒排索引(Inverted Index)
②Document:文檔,Index里面的單條數(shù)據(jù)記錄
③Type:Document可以進(jìn)行分組桐腌,Type就是這種分組拄显,使用Type可以對(duì)Document進(jìn)行過(guò)濾
④Cluster:集群,Elastic是一個(gè)分布式數(shù)據(jù)庫(kù)案站,眾多的節(jié)點(diǎn)組成了一個(gè)集群
⑤Node:單個(gè)elastic實(shí)例為一個(gè)節(jié)點(diǎn)躬审,節(jié)點(diǎn)分為主節(jié)點(diǎn)跟分節(jié)點(diǎn)。當(dāng)一個(gè)節(jié)點(diǎn)被選舉成為主節(jié)點(diǎn)時(shí)蟆盐,它將負(fù)責(zé)管理集群范圍內(nèi)的所有變更承边,例如增加、刪除索引石挂,或者增加博助、刪除節(jié)點(diǎn)等,任何節(jié)點(diǎn)都有可能被選舉成主節(jié)點(diǎn)
⑥分片:數(shù)據(jù)的容器痹愚,分為主分片跟副分片富岳。一個(gè)主分片理論上可以存儲(chǔ)Integer.MAX_VALUE - 128 個(gè)文檔,索引建立時(shí)已經(jīng)確定了主分片的數(shù)量里伯。副分片作為主分片的拷貝城瞎,作為硬件故障時(shí)保護(hù)數(shù)據(jù)不丟失的冗余備份。分片可以分布在同一節(jié)點(diǎn)疾瓮,但是為了做到數(shù)據(jù)備份跟負(fù)載均衡脖镀,一般會(huì)將不同分片分布在不同的節(jié)點(diǎn)上。

全文搜索引擎基本原理-倒排索引

當(dāng)往Elasticsearch插入數(shù)據(jù)時(shí)狼电,會(huì)建立對(duì)應(yīng)的文檔來(lái)存儲(chǔ)數(shù)據(jù)蜒灰,并且根據(jù)分詞規(guī)則對(duì)數(shù)據(jù)進(jìn)行拆分,然后建立不同的詞條跟所在文檔的倒排索引肩碟。當(dāng)進(jìn)行搜索時(shí)强窖,會(huì)對(duì)搜索關(guān)鍵字進(jìn)行拆分,并且匹配倒排索引中維護(hù)的詞條削祈,最終查找出對(duì)應(yīng)的文檔翅溺。
如現(xiàn)在存在兩個(gè)文檔,每個(gè)文檔中的content包括以下內(nèi)容:
1.本文作者是吃雪糕也放辣椒
2.讀完本文給作者點(diǎn)個(gè)贊
然后根據(jù)分詞規(guī)則將文本拆分成詞條髓抑,并且建立倒排索引咙崎,如下所示:


倒排索引表.png

當(dāng)輸入“讀完本文”關(guān)鍵字時(shí),會(huì)匹配到以下結(jié)果:


匹配結(jié)果.png

從上面匹配結(jié)果來(lái)看吨拍,文檔2的匹配度更加高褪猛。如果我們使用僅計(jì)算匹配詞條數(shù)量的簡(jiǎn)單 相似性算法 ,那么羹饰,我們可以說(shuō)伊滋,對(duì)于我們查詢的相關(guān)性來(lái)講碳却,第二個(gè)文檔比第一個(gè)文檔更佳。

Elastic的簡(jiǎn)單使用

①環(huán)境的搭建

1.安裝1.8版本及以上JDK

2.安裝elastic,直接上官網(wǎng)下載解壓即可笑旺,下載鏈接>https://www.elastic.co/cn/downloads/elasticsearch
解壓完后昼浦,cd /安裝目錄/elasticsearch-6.5.4/bin
運(yùn)行 elasticsearch.bat,可以看到elastic已經(jīng)以9300的端口啟動(dòng):

elasticsearch啟動(dòng)圖.png

http端口可以在 /安裝目錄/elasticsearch-6.5.4/config/elasticsearch.yml中進(jìn)行修改

3.安裝IK分詞器,下載鏈接>https://github.com/medcl/elasticsearch-analysis-ik/releases
解壓在 /安裝目錄/elasticsearch-6.5.4/plugins即可

4.安裝可視化界面kibana,下載鏈接>https://www.elastic.co/cn/downloads/kibana
下載完后直接解壓即可筒主,cd /安裝目錄/kibana-6.5.4-windows-x86_64/config,在kibana.yml可以設(shè)置elastic的ip及端口:

kibana.png

然后cd /安裝目錄/kibana-6.5.4-windows-x86_64/bi,進(jìn)入kibana.bat啟動(dòng)

②SpringBoot整合Elasticsearch

1.導(dǎo)入elastic依賴

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>

2.配置節(jié)點(diǎn)

#application.properties
# 配置集群名稱座柱,名稱寫錯(cuò)會(huì)連不上服務(wù)器,默認(rèn)elasticsearch
spring.data.elasticsearch.cluster-name=elasticsearch
# 配置集群節(jié)點(diǎn)
spring.data.elasticsearch.cluster-nodes=localhost:9300

#是否開啟本地存儲(chǔ)
spring.data.elasticsearch.repositories.enabled=true

3.建立模型Demo

@Data
@Document(indexName="shop")
public class Product {
    @Id
    private String id;

    /**
     * searchAnalyzer:分詞器
     * type:字段類型
     * fielddata:預(yù)加載
     */
    @Field(analyzer="ik_smart",searchAnalyzer="ik_smart",type = FieldType.Text,fielddata = true)
    private String title;

    private Integer price;
    
    @Field(analyzer="ik_smart",searchAnalyzer="ik_smart",type = FieldType.Text,fielddata = true)
    private String intro;

    @Field(type= FieldType.Keyword)
    private String brand;
}

4.創(chuàng)建Repository

public interface EsRepository extends ElasticsearchRepository<Product, String> {
}

5.創(chuàng)建業(yè)務(wù)接口

/**
 * @author wangsj
 */
public interface EsProduct {
    /**
     * 添加數(shù)據(jù)
     * @param product 商品對(duì)象
     * @return 返回添加的商品對(duì)象
     */
    Product create(Product product);

    /**
     * 魔魂查詢
     * @param keyword 名字
     * @return 商品集合
     */
    List<Product> search(String keyword);


    /**
     * 高亮查詢
     * @param keyword 搜索關(guān)鍵字
     * @return AggregatedPage
     */
    AggregatedPage<Product> highLightSearch(String keyword);
}

6.業(yè)務(wù)接口實(shí)現(xiàn)類

public class EsProductImpl implements EsProduct {
    @Autowired
    private EsRepository esRepository;
    @Autowired
    private ElasticsearchTemplate template;
    @Override
    public Product create(Product product) {
        Product pro = esRepository.save(product);
        return pro;
    }
    @Override
    public List<Product> search(String keyword) {
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        builder.withQuery(
                QueryBuilders.multiMatchQuery(keyword, "title", "intro")
        );
        builder.withPageable(PageRequest.of(0, 100, Sort.Direction.DESC, "brand"));
        Page<Product> search = esRepository.search(builder.build());
        List<Product> pros = search.getContent();
        return pros;
    }

    @Override
    public AggregatedPage<Product> highLightSearch(String keyword) {
        // Java與JSON互轉(zhuǎn)的工具對(duì)象
        ObjectMapper mapper = new ObjectMapper();

        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        // 設(shè)置查詢哪個(gè)索引中的哪個(gè)類型
        builder.withIndices("shop");
        builder.withQuery(
                QueryBuilders.multiMatchQuery(keyword,
                        "title", "intro")
        );
        builder.withHighlightFields(
                new HighlightBuilder.Field("title")
                        .preTags("<span style='color:red'>").postTags("</span>"),
                new HighlightBuilder.Field("intro")
                        .preTags("<span style='color:red'>").postTags("</span>")
        );
        AggregatedPage<Product> page = template.queryForPage(builder.build(), Product.class,
                new SearchResultMapper(){
                    @Override
                    public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
                        List<T> list = new ArrayList<>();

                        for (SearchHit hit : response.getHits().getHits()) {
                            list.add(mapSearchHit(hit, clazz));
                        }
                        long total = response.getHits().totalHits;
                        return new AggregatedPageImpl<>(list, pageable, total);
                    }
                    @Override
                    public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
                        T t = null;
                        try {
                            t = mapper.readValue(searchHit.getSourceAsString(), type);
                            for (HighlightField field : searchHit.getHighlightFields().values()) {
                                // 替換需要高亮顯示的字段物舒,用到Apache的BeanUtils工具
                                BeanUtils.setProperty(t, field.getName(), field.getFragments()[0].string());
                            }

                        }catch (Exception e){
                            e.printStackTrace();
                            return null;
                        }
                        return t;
                    }
                });

        return page;
    }
}

7.實(shí)例測(cè)試
(1)新增數(shù)據(jù)

    @Test
    public void testCreate(){
        Product product = new Product();
        product.setBrand("三星");
        product.setIntro("性價(jià)比不高的手機(jī)");
        product.setTitle("貴手機(jī)");
        product.setId("3");
        esProduct.create(product);
    }

打開kibana,可以看到elastic中已經(jīng)新建立了一條數(shù)據(jù)


kibana.png

(2)模糊查詢

 @Test
    public void testSearch(){
        List<Product> pros = esProduct.search("甩");
        System.out.println(pros);
    }

輸入搜索關(guān)鍵字為“甩”戏锹,運(yùn)行結(jié)果:


模糊查詢.png

(3)高亮查詢

  @Test
    public void testHighLightSearch(){
        AggregatedPage<Product> page = esProduct.highLightSearch("甩");
        page.forEach(System.out::println);
    }

輸入搜索關(guān)鍵字為“甩”冠胯,運(yùn)行結(jié)果:


image.png

在頁(yè)面直觀的效果類似于往百度輸入搜索關(guān)鍵字,然后返回結(jié)果會(huì)將關(guān)鍵字渲染成紅色


高亮效果.png
③Elasticsearch進(jìn)階

elastic可以進(jìn)行復(fù)雜的聚合運(yùn)算锦针,如桶聚合荠察,還可以進(jìn)行統(tǒng)計(jì)、排序奈搜、分頁(yè)等等悉盆,進(jìn)一步學(xué)習(xí)可以參考官方文檔:>https://www.elastic.co/guide/en/elasticsearch/reference/6.0/search-aggregations.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市馋吗,隨后出現(xiàn)的幾起案子焕盟,更是在濱河造成了極大的恐慌,老刑警劉巖宏粤,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件脚翘,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡绍哎,警方通過(guò)查閱死者的電腦和手機(jī)来农,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)崇堰,“玉大人沃于,你說(shuō)我怎么就攤上這事『;澹” “怎么了繁莹?”我有些...
    開封第一講書人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)饿肺。 經(jīng)常有香客問(wèn)我蒋困,道長(zhǎng),這世上最難降的妖魔是什么敬辣? 我笑而不...
    開封第一講書人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任雪标,我火速辦了婚禮零院,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘村刨。我一直安慰自己告抄,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開白布嵌牺。 她就那樣靜靜地躺著打洼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪逆粹。 梳的紋絲不亂的頭發(fā)上募疮,一...
    開封第一講書人閱讀 52,328評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音僻弹,去河邊找鬼阿浓。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蹋绽,可吹牛的內(nèi)容都是我干的芭毙。 我是一名探鬼主播,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼卸耘,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼退敦!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起蚣抗,我...
    開封第一講書人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤侈百,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后忠聚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體设哗,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年两蟀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了网梢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡赂毯,死狀恐怖战虏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情党涕,我是刑警寧澤烦感,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站膛堤,受9級(jí)特大地震影響手趣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一绿渣、第九天 我趴在偏房一處隱蔽的房頂上張望朝群。 院中可真熱鬧,春花似錦中符、人聲如沸姜胖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)右莱。三九已至,卻和暖如春档插,著一層夾襖步出監(jiān)牢的瞬間慢蜓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工郭膛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胀瞪,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓饲鄙,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親圆雁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子忍级,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容