elasticsearch中文IK+Pinyin分詞器

1、IK分詞器安裝

1.分詞器的做用

分詞顧名思義,就是把一句話分紅一個一個的詞。這個概念在搜索中很重要,好比 This is a banana. 若是按照普通的空格來分詞,分紅this,is,a,banana,的出來的a其實對咱們並無什麼用處。所以須要注意下面的問題:java

  • 1 區分停頓詞(a,or,and這種都屬於停頓詞)
  • 2 大小寫轉換(Bananabanana)
  • 3 時態的轉換....

具體的算法能夠參考http://tartarus.org/~martin/PorterStemmer/,對照的詞語能夠參考這裏http://snowball.tartarus.org/algorithms/porter/diffs.txtnginx

相比中文,就複雜的度了。由於中文不能單純的依靠空格,標點這種進行分詞。就好比中華人民共和國國民,不能簡單的分紅一個詞,也不能粗暴的分紅中華人民共和國國民人民中華這些也都算一個詞!git

所以常見的分詞算法就是拿一個標準的詞典,關鍵詞都在這個詞典裏面。而後按照幾種規則去查找有沒有關鍵詞,好比:github

  • 正向最大匹配(從左到右)
  • 逆向最大匹配(從右到左)
  • 最少切分
  • 雙向匹配(從左掃描一次,從右掃描一次)

IK,elasticsearch-analysis-ik提供了兩種方式,ik_smart就是最少切分,ik_max_word則爲細粒度的切分(多是雙向,沒看過源碼)算法

2.安裝

瞭解了分詞器的背景後,就能夠看一下如何在Elasticsearch重安裝分詞器了。app

ik GitHub地址:https://github.com/medcl/elasticsearch-analysis-ikcurl

插件包地址:https://github.com/medcl/elasticsearch-analysis-ik/releaseselasticsearch

安裝方式:maven

1.解壓對應版本的插件包到 your-es-directory/plugins/ik,重啓es就ok;ide

2.下載源碼,將編譯好的jar包導入到 your-es-directory/plugins/ik,重啓es就ok;

注意:es 與 ik版本必定要對應。

2、IK分詞器使用測試

1.create a index

curl -XPUT http://localhost:9200/ik_index

2.create a mapping

curl -XPOST http://localhost:9200/ik_index/fulltext/_mapping
{
        "properties": {
            "content": {
                "type": "text",
                "analyzer": "ik_max_word",
                "search_analyzer": "ik_max_word"
            }
        }
    
}

3.index some docs

curl -XPOST http://localhost:9200/index/fulltext/1 -d'
{"content":"美國留給伊拉克的是個爛攤子嗎"}
'
curl -XPOST http://localhost:9200/index/fulltext/2 -d'
{"content":"公安部:各地校車將享最高路權"}
'
curl -XPOST http://localhost:9200/index/fulltext/3 -d'
{"content":"中韓漁警衝突調查:韓警平均天天扣1艘中國漁船"}
'
curl -XPOST http://localhost:9200/index/fulltext/4 -d'
{"content":"中國駐洛杉磯領事館遭亞裔男子槍擊 嫌犯已自首"}
'

4.query with highlighting

curl -XPOST http://localhost:9200/index/fulltext/_search  -d'
{
    "query" : { "match" : { "content" : "中國" }},
    "highlight" : {
        "pre_tags" : ["<tag1>", "<tag2>"],
        "post_tags" : ["</tag1>", "</tag2>"],
        "fields" : {
            "content" : {}
        }
    }
}
'

5.Dictionary Configuration

IKAnalyzer.cfg.xml can be located at plugins/ik/config/IKAnalyzer.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
	<comment>IK Analyzer 擴展配置</comment>
	<!--用戶能夠在這裏配置本身的擴展字典 -->
	<entry key="ext_dict">custom/mydict.dic;custom/single_word_low_freq.dic</entry>
	 <!--用戶能夠在這裏配置本身的擴展中止詞字典-->
	<entry key="ext_stopwords">custom/ext_stopword.dic</entry>
 	<!--用戶能夠在這裏配置遠程擴展字典 -->
	<entry key="remote_ext_dict">location</entry>
 	<!--用戶能夠在這裏配置遠程擴展中止詞字典-->
	<entry key="remote_ext_stopwords">http://xxx.com/xxx.dic</entry>
</properties>

熱更新 IK 分詞使用方法

目前該插件支持熱更新 IK 分詞,經過上文在 IK 配置文件中提到的以下配置

<!--用戶能夠在這裏配置遠程擴展字典 -->
	<entry key="remote_ext_dict">location</entry>
 	<!--用戶能夠在這裏配置遠程擴展中止詞字典-->
	<entry key="remote_ext_stopwords">location</entry>

其中 location 是指一個 url,好比 http://yoursite.com/getCustomDict,該請求只需知足如下兩點便可完成分詞熱更新。

  1. 該 http 請求須要返回兩個頭部(header),一個是 Last-Modified,一個是 ETag,這二者都是字符串類型,只要有一個發生變化,該插件就會去抓取新的分詞進而更新詞庫。

  2. 該 http 請求返回的內容格式是一行一個分詞,換行符用 \n 便可。

知足上面兩點要求就能夠實現熱更新分詞了,不須要重啓 ES 實例。

能夠將需自動更新的熱詞放在一個 UTF-8 編碼的 .txt 文件裏,放在 nginx 或其餘簡易 http server 下,當 .txt 文件修改時,http server 會在客戶端請求該文件時自動返回相應的 Last-Modified 和 ETag。能夠另外作一個工具來從業務系統提取相關詞彙,並更新這個 .txt 文件。

3、pinyin分詞器下載與安裝

pinyin分詞器可讓用戶輸入拼音,就能查找到相關的關鍵詞。好比在某個商城搜索中,輸入shuihu,就能匹配到水壺。這樣的體驗仍是很是好的。

pinyin分詞器的安裝與IK是同樣的,這裏就省略掉了。

這個分詞器在1.8版本中,提供了兩種分詞規則:

  • pinyin,就是普通的把漢字轉換成拼音;
  • pinyin_first_letter,提取漢字的拼音首字母

github: https://github.com/medcl/elasticsearch-analysis-pinyin

安裝: 在github下載源碼,idea import 源碼,修改pom.xml文件中es版本號,執行maven的package命令,在target目錄下的*.zip文件即是pinyin分詞器的插件包。安裝方式同上IK分詞器。

插件介紹

該插件包括分析器:pinyin,標記器:pinyin和令牌過濾器: pinyin。

**可選參數**

keep_first_letter : 啓用此選項時,例如:劉德華> ldh,默認值:true
keep_separate_first_letter : 啓用該選項時,將保留第一個字母分開,例如:劉德華> l,d,h,默認:假的,注意:查詢結果也許是太模糊,因爲長期過頻
limit_first_letter_length : 設置first_letter結果的最大長度,默認值:16
keep_full_pinyin : 當啓用該選項,例如:劉德華> [ liu,de,hua],默認值:true
keep_joined_full_pinyin : 啓用此選項時,例如:劉德華> [ liudehua],默認值:false
keep_none_chinese : 在結果中保留非中文字母或數字,默認值:true
keep_none_chinese_together : 保持非中國信一塊兒,默認值:true,如:DJ音樂家- > DJ,yin,yue,jia,當設置爲false,例如:DJ音樂家- > D,J,yin,yue,jia,注意:keep_none_chinese必須先啓動
keep_none_chinese_in_first_letter : 第一個字母不能是中文,例如:劉德華AT2016- > ldhat2016,default:true
keep_none_chinese_in_joined_full_pinyin : 保持非中文字母加入完整拼音,例如:劉德華2016- > liudehua2016,默認:false
none_chinese_pinyin_tokenize : 打破非中國信成單獨的拼音項,若是他們拼音,默認值:true,如:liudehuaalibaba13zhuanghan- > liu,de,hua,a,li,ba,ba,13,zhuang,han,注意: keep_none_chinese和keep_none_chinese_together應首先啓用
keep_original : 當啓用此選項時,也將保留原始輸入,默認值:false
lowercase : 小寫非中文字母,默認值:true
trim_whitespace : 默認值:true
remove_duplicated_term : 當啓用此選項時,將刪除重複項以保存索引,例如:de的> de,默認值:false注意:位置相關查詢可能受影響

4、pinyin分詞器使用測試

1.使用自定義拼音分析器建立索引

curl -XPUT http://localhost:9200/medcl
{
    "index" : {
        "analysis" : {
            "analyzer" : {
                "pinyin_analyzer" : {
                    "tokenizer" : "my_pinyin"
                    }
            },
            "tokenizer" : {
                "my_pinyin" : {
                    "type" : "pinyin",
                    "keep_separate_first_letter" : false,
                    "keep_full_pinyin" : true,
                    "keep_original" : true,
                    "limit_first_letter_length" : 16,
                    "lowercase" : true,
                    "remove_duplicated_term" : true
                }
            }
        }
    }
}

2.測試分析器,分析一箇中文名字,好比劉德華

http://localhost:9200/medcl/_analyze?text=%e5%88%98%e5%be%b7%e5%8d%8e&analyzer=pinyin_analyzer

3.建立映射

properties 中定義了特定字段的分析方式。在上面的例子中,僅僅設置了content的分析方法。

  • type,字段的類型爲string,只有string類型才涉及到分詞,像是數字之類的是不須要分詞的。
  • store,定義字段的存儲方式,no表明不單獨存儲,查詢的時候會從_source中解析。當你頻繁的針對某個字段查詢時,能夠考慮設置成true。
  • term_vector,定義了詞的存儲方式,with_position_offsets,意思是存儲詞語的偏移位置,在結果高亮的時候有用。
  • analyzer,定義了索引時的分詞方法
  • search_analyzer,定義了搜索時的分詞方法
  • include_in_all,定義了是否包含在_all字段中
  • boost,是跟計算分值相關的
curl -XPOST http://localhost:9200/medcl/folks/_mapping
{
    "folks": {
        "properties": {
            "name": {
                "type": "keyword",
                "fields": {
                    "pinyin": {
                        "type": "text",
                        "store": "no",
                        "term_vector": "with_offsets",
                        "analyzer": "pinyin_analyzer",
                        "boost": 10
                    }
                }
            }
        }
    }
}

四、搜索

http://localhost:9200/medcl/folks/_search?q=name:劉德華
http://localhost:9200/medcl/folks/_search?q=name.pinyin:劉
http://localhost:9200/medcl/folks/_search?q=name.pinyin:liu
http://localhost:9200/medcl/folks/_search?q=name.pinyin:ldh
http://localhost:9200/medcl/folks/_search?q=name.pinyin:de+hua

5.使用拼音 - TokenFilter

curl -XPUT http://localhost:9200/medcl1
{
    "index" : {
        "analysis" : {
            "analyzer" : {
                "user_name_analyzer" : {
                    "tokenizer" : "whitespace",
                    "filter" : "pinyin_first_letter_and_full_pinyin_filter"
                }
            },
            "filter" : {
                "pinyin_first_letter_and_full_pinyin_filter" : {
                    "type" : "pinyin",
                    "keep_first_letter" : true,
                    "keep_full_pinyin" : false,
                    "keep_none_chinese" : true,
                    "keep_original" : false,
                    "limit_first_letter_length" : 16,
                    "lowercase" : true,
                    "trim_whitespace" : true,
                    "keep_none_chinese_in_first_letter" : true
                }
            }
        }
    }
}

Token Test:劉德華 張學友 郭富城 黎明 四大天王

curl -XGET http://localhost:9200/medcl1/_analyze?text=劉德華+張學友+郭富城+黎明+四大天王&analyzer=user_name_analyzer
{
  "tokens" : [
    {
      "token" : "ldh",
      "start_offset" : 0,
      "end_offset" : 3,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "zxy",
      "start_offset" : 4,
      "end_offset" : 7,
      "type" : "word",
      "position" : 1
    },
    {
      "token" : "gfc",
      "start_offset" : 8,
      "end_offset" : 11,
      "type" : "word",
      "position" : 2
    },
    {
      "token" : "lm",
      "start_offset" : 12,
      "end_offset" : 14,
      "type" : "word",
      "position" : 3
    },
    {
      "token" : "sdtw",
      "start_offset" : 15,
      "end_offset" : 19,
      "type" : "word",
      "position" : 4
    }
  ]
}

6.使用短語查詢

  • option 1

    PUT /medcl/
      {
          "index" : {
              "analysis" : {
                  "analyzer" : {
                      "pinyin_analyzer" : {
                          "tokenizer" : "my_pinyin"
                          }
                  },
                  "tokenizer" : {
                      "my_pinyin" : {
                          "type" : "pinyin",
                          "keep_first_letter":false,
                          "keep_separate_first_letter" : false,
                          "keep_full_pinyin" : true,
                          "keep_original" : false,
                          "limit_first_letter_length" : 16,
                          "lowercase" : true
                      }
                  }
              }
          }
      }
      GET /medcl/folks/_search
      {
        "query": {"match_phrase": {
          "name.pinyin": "劉德華"
        }}
      }
  • option 2

    PUT /medcl/
      {
          "index" : {
              "analysis" : {
                  "analyzer" : {
                      "pinyin_analyzer" : {
                          "tokenizer" : "my_pinyin"
                          }
                  },
                  "tokenizer" : {
                      "my_pinyin" : {
                          "type" : "pinyin",
                          "keep_first_letter":false,
                          "keep_separate_first_letter" : true,
                          "keep_full_pinyin" : false,
                          "keep_original" : false,
                          "limit_first_letter_length" : 16,
                          "lowercase" : true
                      }
                  }
              }
          }
      }
    
      POST /medcl/folks/andy
      {"name":"劉德華"}
    
      GET /medcl/folks/_search
      {
        "query": {"match_phrase": {
          "name.pinyin": "劉德h"
        }}
      }
    
      GET /medcl/folks/_search
      {
        "query": {"match_phrase": {
          "name.pinyin": "劉dh"
        }}
      }
    
      GET /medcl/folks/_search
      {
        "query": {"match_phrase": {
          "name.pinyin": "dh"
        }}  
    }

4、分詞流程

整個流程大概是:單詞 ====》Character Filter 預處理 =====》tokenizer分詞 ====》 token filter對分詞進行再處理。

  1. 單詞或文檔先通過Character Filters;Character Filters的做用就是對文本進行一個預處理,例如把文本中全部「&」換成「and」,把「?」去掉等等操做。
  2. 以後就進入了十分重要的tokenizers模塊了,Tokenizers的做用是進行分詞,例如,「tom is a good doctor .」。通過Character Filters去掉句號「.」(假設)後,分詞器Tokenizers會將這個文本分出不少詞來:「tom」、「is」、「a」、「good」、「doctor」。
  3. 通過分詞以後的集合,最後會進入Token Filter詞單元模塊進行處理,此模塊的做用是對已經分詞後的集合(tokens)單元再進行操做,例如把「tom」再次拆分紅「t」、「o」、「m」等操做。最後得出來的結果集合,就是最終的集合

5、參考

分詞配置詳解: http://blog.csdn.net/napoay/article/details/53907921

分詞過程: http://blog.csdn.net/hu948162999/article/details/68922035

分詞原理: http://blog.csdn.net/i6448038/article/details/51509439(推薦)

相關文章
相關標籤/搜索