正排索引
文檔ID到文檔內(nèi)容桥胞、單詞的關(guān)聯(lián)關(guān)系。比如書的目錄頁(yè)對(duì)應(yīng)正排索引(指明章節(jié)名稱,指明頁(yè)數(shù))用于查看章節(jié)夭委。
倒排索引
單詞到文檔ID的關(guān)聯(lián)關(guān)系。比如索引頁(yè)對(duì)應(yīng)倒排索引(指明關(guān)鍵詞募强、指明頁(yè)數(shù))用于關(guān)鍵詞查找
倒排索引是搜索引擎的核心株灸,主要包含兩個(gè)部分:
單詞詞典(Term Dictionary)
- 記錄所有文檔的單詞,一般都比較大擎值。
- 記錄單詞到倒排列表的關(guān)聯(lián)信息慌烧。
倒排列表(Posting List)
記錄了單詞對(duì)應(yīng)的文檔集合,由倒排索引項(xiàng)組成幅恋。倒排索引項(xiàng)包含如下信息:
- 文檔ID杏死,用于獲取原始信息。
- 單詞頻率捆交,記錄該單詞在該文檔中的出現(xiàn)次數(shù)淑翼,用于后續(xù)相關(guān)性算分。
- 位置品追,記錄單詞在文檔中的粉刺位置玄括,用于做詞語(yǔ)搜索。
- 偏移肉瓦,記錄單詞在文檔的開始和結(jié)束位置遭京,用于做高亮顯示。
分詞
分詞是指將文本轉(zhuǎn)換成一系列單詞的過程泞莉,也可以叫做文本分析哪雕,在es里面成為Analysis
分詞器是Elasticsearch中專門處理分詞的組件,英文為Analyzer鲫趁,其組成如下:
Character Filters
針對(duì)原始文本進(jìn)行處理斯嚎,比如去除html特殊標(biāo)記符。
Tokenizer
將原始文本按照一定規(guī)則切分為單詞。
Token Filters
針對(duì)Tokenizer處理的單詞進(jìn)行在加工堡僻,比如轉(zhuǎn)小寫糠惫,刪除或新增等處理。
分詞器——調(diào)用順序
Analyze_api
Elasticsearch提供了一個(gè)測(cè)試分詞的api接口钉疫,方便驗(yàn)證分詞效果硼讽,endpoint是_analyze
可以直接指定Analyzer進(jìn)行測(cè)試。
可以直接指定索引中的字段進(jìn)行測(cè)試牲阁。
可以自定義分詞器進(jìn)行測(cè)試固阁。
-
直接指定analyze進(jìn)行測(cè)試,接口如下:
-
直接指定索引中的字段進(jìn)行測(cè)試咨油,接口如下:
-
自定義分詞器進(jìn)行測(cè)試您炉,接口如下:
Elasticsearch自帶分詞器
中文分詞
難點(diǎn):
中文分詞指的是將一個(gè)漢字序列切分成一個(gè)一個(gè)單獨(dú)的詞,在英文中單詞之間是以空格作為自然分隔符役电,但漢語(yǔ)中則沒有形式上的分隔符。
上下文不同分詞效果迥異棉胀,比如交叉歧義問題法瑟,比如下面兩種分詞都合理。
乒乓球拍/賣/完了
乒乓球/拍/買完了
常用分詞系統(tǒng)
IK
- 實(shí)現(xiàn)中英文單詞的切分唁奢,支持ik_smart霎挟、ik_maxword等模式
- 可自定義詞庫(kù),支持熱更新分詞詞典
- https://github.com/medcl/elasticsearch-analysis-ik
- 下載地址:https://github.com/medcl/elasticsearch-analysis-ik/releases
ieba
- python中最流行的分詞系統(tǒng)麻掸,支持分詞和詞性標(biāo)注
- 支持繁體分詞酥夭,自定義詞典,并行分詞等
- https://github.com/sing1ee/elasticsearch-jieba-plugin
基于自然語(yǔ)言處理的分詞系統(tǒng)
HanLp
- 由一系列模型與算法組成的Java工具包脊奋,目標(biāo)是普及自然語(yǔ)言處理在生產(chǎn)環(huán)境中的應(yīng)用
- https://github.com/hankcs/HanLp
thulac
- THU Lexical Analyzer for Chinese熬北,由清華大學(xué)自然語(yǔ)言處理與社會(huì)人文計(jì)算實(shí)驗(yàn)室研制推出的一套中文詞法分析工具包,具有中文分詞和詞性標(biāo)注功能
- https://github.com/microbun/elasticsearch-thulac-plugin
自定義分詞
當(dāng)自帶的分詞無法滿足需求時(shí)诚隙,可自定義分詞
通過自定義Character Filters讶隐、Tokenizer、Token Filters實(shí)現(xiàn)
Character Filters
在Tokenizer之前對(duì)原始文本進(jìn)行處理久又,比如增加巫延、刪除或替換字符等。
-
自帶的如下:
- HTML Strip 去除html標(biāo)簽和轉(zhuǎn)換html實(shí)體地消。
- Mapping進(jìn)行字符替換操作炉峰。
- Pattern Replace進(jìn)行正則匹配替換。
會(huì)影響后續(xù)Tokenizer解析的postion和offset信息脉执。
Tokenizer
- 將原始文本按照一定規(guī)則切分為單詞(term or token)
- 自帶的如下:
- standard 按照單詞進(jìn)行分割疼阔。
- letter 按照非字符類進(jìn)行分割。
- whitespace 按照空格進(jìn)行分割适瓦。
- UAX URL Email 按照standard 分割竿开,但不會(huì)分割郵箱和url谱仪。
- NGram和Edge NGram連詞分割。
- Path Hierarchy 按照文件路徑進(jìn)行分割否彩。
Token Filters
- 對(duì)于Tokenizer輸出的單詞(term)進(jìn)行增加疯攒、刪除、修改等操作列荔。
- 自帶的如下:
- lowercase 將所有的term轉(zhuǎn)換為小寫敬尺。
- stop刪除stop words。
- NGram和Edge NGram連詞分割贴浙。
- Synonym添加近義詞的term砂吞。
自定義分詞的api
自定義分詞需要在索引的配置中設(shè)定,如下所示:
分詞會(huì)在如下兩個(gè)時(shí)機(jī)使用:
- 創(chuàng)建或更新文檔時(shí)(Index Time)崎溃,會(huì)對(duì)相應(yīng)的文檔進(jìn)行分詞處理蜻直。
- 查詢時(shí)(Search Time),會(huì)對(duì)查詢語(yǔ)句進(jìn)行分詞袁串。
索引時(shí)分詞是通過配置Index Mapping中每個(gè)字段的analyzer屬性實(shí)現(xiàn)的概而,如下:
-
不指定分詞時(shí),使用默認(rèn)分詞standard
查詢時(shí)分詞的指定方式有如下幾種:
- 查詢的時(shí)候通過analyzer指定分詞器囱修。
-
通過index mapping設(shè)置search_analyzer實(shí)現(xiàn)
ik分詞器安裝與使用
ik分詞器下載與安裝
- 1赎瑰、下載與ES對(duì)應(yīng)的版本即可,下載地址:https://github.com/medcl/elasticsearch-analysis-ik/releases
*2破镰、解壓餐曼,將文件復(fù)制到es安裝目錄/plugins/ik目錄下即可
- 3、重啟elasticsearch
ik分詞器基礎(chǔ)知識(shí)
ik_max_word:會(huì)將文本做最細(xì)粒度的拆分鲜漩,比如會(huì)將"中華人民共和國(guó)人民大會(huì)堂"拆分為"中華人民共和國(guó)源譬、中華人民、中華宇整、華人瓶佳、人民、人民共和國(guó)鳞青、人民大會(huì)堂霸饲、人民大會(huì)、大會(huì)堂"臂拓,會(huì)窮盡各種可能的組合厚脉。
ik_smart:會(huì)做最粗粒度的拆分,比如會(huì)將"中華人民共和國(guó)人民大會(huì)堂"拆分為"中華人民共和國(guó)胶惰、人民大會(huì)堂"傻工。
ik分詞器的使用
存儲(chǔ)時(shí)使用ik_max_word,搜索時(shí)使用ik_smart
因?yàn)楹罄m(xù)的keyword和text設(shè)計(jì)分詞問題,這里給出分詞最佳實(shí)踐中捆。即存儲(chǔ)時(shí)時(shí)使用ik_max_word鸯匹,搜索時(shí)分詞器用ik_smart,這樣索引時(shí)最大化的將內(nèi)容分詞泄伪,搜索時(shí)更精確的搜索到想要的結(jié)果殴蓬。
PUT /index
{
"mappings": {
"peoperties":{
"text":{
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
}
}
}
}
ik分詞器配置文件
- ik配置文件地址
/es/plugins/ik/config
目錄 - IKAnalyzer.cfg.xml:用來配置自定義詞庫(kù)。
- main.dic:ik原生內(nèi)置的中文詞庫(kù)蟋滴,總共有27萬多條染厅,只要是這些單詞,都會(huì)被分到一起津函。
- preposition.dic:介詞肖粮。
- quantifier.dic:放了一些單位相關(guān)的詞,量詞尔苦。
- suffix.dic:放了一些后綴涩馆。
- surname.dic:中國(guó)的姓氏。
- stopword.dic:英文停用詞允坚。
ik原生最重要的兩個(gè)配置文件:
- main.dic:包含了原生的中文詞語(yǔ)凌净,會(huì)按照這里面的詞去進(jìn)行分詞。
- stopword.dic:包含了英文的停用詞屋讶。
一般向停用詞會(huì)在分詞的時(shí)候,直接被干掉须教,不會(huì)建立在倒排索引中皿渗。
自定義詞庫(kù)
- 1、自己建立詞庫(kù):每年都會(huì)涌現(xiàn)一些特殊的流行詞轻腺,網(wǎng)紅乐疆、藍(lán)瘦香菇、喊麥贬养、鬼畜等挤土,一般不會(huì)在ik的原生詞典里。
自己補(bǔ)充自己的最新的詞語(yǔ)误算,到ik詞庫(kù)里面仰美。
在IKAnalyzer.cfg.xml文件中ext_dict標(biāo)簽中,創(chuàng)建mydict.dic儿礼。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 擴(kuò)展配置</comment>
<!--用戶可以在這里配置自己的擴(kuò)展字典 -->
<entry key="ext_dict">mydict.dic</entry>
<!--用戶可以在這里配置自己的擴(kuò)展停止詞字典-->
<entry key="ext_stopwords">mystopwords.dic</entry>
<!--用戶可以在這里配置遠(yuǎn)程擴(kuò)展字典 -->
<!-- <entry key="remote_ext_dict">words_location</entry> -->
<!--用戶可以在這里配置遠(yuǎn)程擴(kuò)展停止詞字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
- 2咖杂、自己建立停用詞庫(kù),比如了蚊夫、的诉字、啥、么等,可能并不想建立索引讓人家搜索壤圃。
custom/ext_stopword.dic陵霉,已經(jīng)有了常用的中文停用詞,可以自己補(bǔ)充自己的中文停用詞伍绳,然后重啟es踊挠。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 擴(kuò)展配置</comment>
<!--用戶可以在這里配置自己的擴(kuò)展字典 -->
<entry key="ext_dict">mydict.dic</entry>
<!--用戶可以在這里配置自己的擴(kuò)展停止詞字典-->
<entry key="ext_stopwords">mystopwords.dic</entry>
<!--用戶可以在這里配置遠(yuǎn)程擴(kuò)展字典 -->
<!-- <entry key="remote_ext_dict">words_location</entry> -->
<!--用戶可以在這里配置遠(yuǎn)程擴(kuò)展停止詞字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
使用mysql熱更新詞庫(kù)
熱更新
每次都是在es的擴(kuò)展詞典中,手動(dòng)添加新詞墨叛,很坑止毕。
- 每次添加完,都要重啟es才能生效漠趁,非常麻煩扁凛。
- es是分布式的可能有數(shù)百個(gè)節(jié)點(diǎn),你不能每一次都一個(gè)一個(gè)節(jié)點(diǎn)上面去修改闯传。
es不停機(jī)谨朝,我們直接在外部某個(gè)地方添加新的詞語(yǔ),es中立即熱加載到這些新詞語(yǔ)甥绿。
熱更新方案
- 1字币、基于ik分詞器原生支持的熱更新方案,部署一個(gè)web服務(wù)器共缕,提供一個(gè)http接口洗出,通過modified和tag兩個(gè)http響應(yīng)頭,來提供詞語(yǔ)的熱更新图谷。
- 2翩活、修改ik分詞器源碼,然后手動(dòng)支持從mysql中每隔一段時(shí)間便贵,自動(dòng)加載新的詞庫(kù)菠镇。
用第二種方案,第一種方案ik官方和社區(qū)都不建議采用承璃,覺得不太穩(wěn)定利耍。
1、基于ik分詞器原生支持的熱更新方案
- 1)盔粹、ik官方文檔說明
目前該插件支持熱更新 IK 分詞隘梨,通過上文在 IK 配置文件中提到的如下配置
<!--用戶可以在這里配置遠(yuǎn)程擴(kuò)展字典 -->
<entry key="remote_ext_dict">location</entry>
<!--用戶可以在這里配置遠(yuǎn)程擴(kuò)展停止詞字典-->
<entry key="remote_ext_stopwords">location</entry>
其中 location 是指一個(gè) url,比如 http://yoursite.com/getCustomDict玻佩,該請(qǐng)求只需滿足以下兩點(diǎn)即可完成分詞熱更新出嘹。
- A、該 http 請(qǐng)求需要返回兩個(gè)頭部(header)咬崔,一個(gè)是 Last-Modified税稼,一個(gè)是 ETag烦秩,這兩者都是字符串類型,只要有一個(gè)發(fā)生變化郎仆,該插件就會(huì)去抓取新的分詞進(jìn)而更新詞庫(kù)只祠。
- B、該 http 請(qǐng)求返回的內(nèi)容格式是一行一個(gè)分詞扰肌,換行符用 \n 即可抛寝。
滿足上面兩點(diǎn)要求就可以實(shí)現(xiàn)熱更新分詞了,不需要重啟 ES 實(shí)例曙旭。
可以將需自動(dòng)更新的熱詞放在一個(gè) UTF-8 編碼的xxx.txt
文件里盗舰,放在 nginx 或其他簡(jiǎn)易 http server
下,當(dāng)xxx.txt
文件修改時(shí)桂躏,http server 會(huì)在客戶端請(qǐng)求該文件時(shí)自動(dòng)返回相應(yīng)的 Last-Modified 和 ETag钻趋。可以另外做一個(gè)工具來從業(yè)務(wù)系統(tǒng)提取相關(guān)詞匯剂习,并更新這個(gè)xxx.txt
文件蛮位。
個(gè)人體會(huì):nginx方式比較簡(jiǎn)單容易實(shí)現(xiàn),建議使用鳞绕;
- 2)失仁、在服務(wù)中實(shí)現(xiàn)http請(qǐng)求,并連接數(shù)據(jù)庫(kù)實(shí)現(xiàn)熱詞管理實(shí)例:
- A们何、編寫http請(qǐng)求服務(wù)接口demo
@RestController
@RequestMapping("/keyWord")
@Slf4j
public class KeyWordDict {
private String lastModified = new Date().toString();
private String etag = String.valueOf(System.currentTimeMillis());
@RequestMapping(value = "/hot", method = {RequestMethod.GET,RequestMethod.HEAD}, produces="text/html;charset=UTF-8")
public String getHotWordByOracle(HttpServletResponse response,Integer type){
response.setHeader("Last-Modified",lastModified);
response.setHeader("ETag",etag);
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
String sql = "";
final ArrayList<String> list = new ArrayList<String>();
StringBuilder words = new StringBuilder();
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection(
"jdbc:oracle:thin:@192.168.114.13:1521:xe",
"test",
"test"
);
if(ObjectUtils.isEmpty(type)){
type = 99;
}
switch (type){
case 0:
sql = "select word from IK_HOT_WORD where type=0 and status=0";
break;
case 1:
sql = "select word from IK_HOT_WORD where type=1 and status=0";
break;
default:
sql = "select word from IK_HOT_WORD where type=99";
break;
}
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
while(rs.next()) {
String theWord = rs.getString("word");
System.out.println("hot word from mysql: " + theWord);
words.append(theWord);
words.append("\n");
}
return words.toString();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
log.error("資源關(guān)閉異常:",e);
}
}
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
log.error("資源關(guān)閉異常:",e);
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
log.error("資源關(guān)閉異常:",e);
}
}
}
return null;
}
@RequestMapping(value = "/update", method = RequestMethod.GET)
public void updateModified(){
lastModified = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date());
etag = String.valueOf(System.currentTimeMillis());
}
}
注:
updateModified方法為單獨(dú)更新lastModified與etag萄焦,用于判斷ik是否需要重新加載遠(yuǎn)程詞庫(kù),具體關(guān)聯(lián)數(shù)據(jù)庫(kù)操作代碼時(shí)自行擴(kuò)展
- B冤竹、ik配置文件修改
- 文件目錄:/data/elasticsearch-7.3.0/plugins/ik/config/IKAnalyzer.cfg.xml
- 遠(yuǎn)程調(diào)用方法填寫在“用戶可以在這里配置遠(yuǎn)程擴(kuò)展字典”下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 擴(kuò)展配置</comment>
<!--用戶可以在這里配置自己的擴(kuò)展字典 -->
<entry key="ext_dict"></entry>
<!--用戶可以在這里配置自己的擴(kuò)展停止詞字典-->
<entry key="ext_stopwords"></entry>
<!--用戶可以在這里配置遠(yuǎn)程擴(kuò)展字典 -->
<entry key="remote_ext_dict">http://192.168.xx.xx:8080/keyWord/hot?type=0</entry>
<!--用戶可以在這里配置遠(yuǎn)程擴(kuò)展停止詞字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
重寫ik源碼連接mysql/oracle更新詞庫(kù)
1楷扬、下載ik源碼(下載對(duì)應(yīng)版本)
https://github.com/medcl/elasticsearch-analysis-ik/releases
ik分詞器是一個(gè)標(biāo)準(zhǔn)的java maven工程,直接導(dǎo)入idea就可看到源碼贴见。2、修改ik插件源碼(以mysql為例)
1)躲株、添加jdbc配置文件
在項(xiàng)目根目錄下的config目錄中添加config\jdbc-reload.properties配置文件:
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/es?serverTimezone=UTC
jdbc.user=root
jdbc.password=yibo
jdbc.reload.sql=select word from hot_words
jdbc.reload.stopword.sql=select stopword as word from hot_stopwords
jdbc.reload.interval=5000
- 2)片部、在Dictionary類的同級(jí)目錄下新建HotDictReloadThread類
/**
* @Description: 加載字典線程
*/
public class HotDictReloadThread implements Runnable {
private static final Logger log = ESPluginLoggerFactory.getLogger(HotDictReloadThread.class.getName());
@Override
public void run() {
log.info("[--------]reload hot dict from mysql");
Dictionary.getSingleton().reLoadMainDict();
}
}
- 3)、在Dictionary類initial方法中新增代碼
public static synchronized void initial(Configuration cfg) {
if (singleton == null) {
synchronized (Dictionary.class) {
if (singleton == null) {
singleton = new Dictionary(cfg);
singleton.loadMainDict();
singleton.loadSurnameDict();
singleton.loadQuantifierDict();
singleton.loadSuffixDict();
singleton.loadPrepDict();
singleton.loadStopWordDict();
//!!!!!!!!mysql監(jiān)控線程 新增代碼
new Thread(new HotDictReloadThread()).start();
if(cfg.isEnableRemoteDict()){
// 建立監(jiān)控線程
for (String location : singleton.getRemoteExtDictionarys()) {
// 10 秒是初始延遲可以修改的 60是間隔時(shí)間 單位秒
pool.scheduleAtFixedRate(new Monitor(location), 10, 60, TimeUnit.SECONDS);
}
for (String location : singleton.getRemoteExtStopWordDictionarys()) {
pool.scheduleAtFixedRate(new Monitor(location), 10, 60, TimeUnit.SECONDS);
}
}
}
}
}
}
- 4)霜定、在Dictionary類loadMainDict方法中新增代碼
/**
* 加載主詞典及擴(kuò)展詞典
*/
private void loadMainDict() {
// 建立一個(gè)主詞典實(shí)例
_MainDict = new DictSegment((char) 0);
// 讀取主詞典文件
Path file = PathUtils.get(getDictRoot(), Dictionary.PATH_DIC_MAIN);
loadDictFile(_MainDict, file, false, "Main Dict");
// 加載擴(kuò)展詞典
this.loadExtDict();
// 加載遠(yuǎn)程自定義詞庫(kù)
this.loadRemoteExtDict();
//從mysql中加載熱更新詞典 新增代碼
this.loadMySQLExtDict();
}
- 5)档悠、在Dictionary類loadStopWordDict方法中新增代碼
/**
* 加載用戶擴(kuò)展的停止詞詞典
*/
private void loadStopWordDict() {
// 建立主詞典實(shí)例
_StopWords = new DictSegment((char) 0);
// 讀取主詞典文件
Path file = PathUtils.get(getDictRoot(), Dictionary.PATH_DIC_STOP);
loadDictFile(_StopWords, file, false, "Main Stopwords");
// 加載擴(kuò)展停止詞典
List<String> extStopWordDictFiles = getExtStopWordDictionarys();
if (extStopWordDictFiles != null) {
for (String extStopWordDictName : extStopWordDictFiles) {
logger.info("[Dict Loading] " + extStopWordDictName);
// 讀取擴(kuò)展詞典文件
file = PathUtils.get(extStopWordDictName);
loadDictFile(_StopWords, file, false, "Extra Stopwords");
}
}
// 加載遠(yuǎn)程停用詞典
List<String> remoteExtStopWordDictFiles = getRemoteExtStopWordDictionarys();
for (String location : remoteExtStopWordDictFiles) {
logger.info("[Dict Loading] " + location);
List<String> lists = getRemoteWords(location);
// 如果找不到擴(kuò)展的字典,則忽略
if (lists == null) {
logger.error("[Dict Loading] " + location + "加載失敗");
continue;
}
for (String theWord : lists) {
if (theWord != null && !"".equals(theWord.trim())) {
// 加載遠(yuǎn)程詞典數(shù)據(jù)到主內(nèi)存中
logger.info(theWord);
_StopWords.fillSegment(theWord.trim().toLowerCase().toCharArray());
}
}
}
//!!!!!!!!從mysql中加載停用詞 新增代碼
this.loadMySQLStopWordDict();
}
- 6)望浩、在Dictionary類新增靜態(tài)代碼塊辖所,加載db驅(qū)動(dòng)
private static Properties prop = new Properties();
static {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
logger.error("error",e);
}
}
- 7)、在Dictionary類新增loadMySQLExtDict方法磨德,從mysql中加載熱更新詞典
/**
* 從mysql中加載熱更新詞典
*/
private void loadMySQLExtDict(){
Connection conn = null;
Statement state = null;
ResultSet rs = null;
try{
Path file = PathUtils.get(getDictRoot(),"jdbc-reload.properties");
prop.load(new FileInputStream(file.toFile()));
for (Object key : prop.keySet()) {
logger.info("[--------]" + key +"=" + prop.getProperty(String.valueOf(key)));
}
logger.info("[--------]query hot dict from mysql," + prop.getProperty("jdbc.reload.sql") + "......");
// 創(chuàng)建數(shù)據(jù)連接
conn = DriverManager.getConnection(
prop.getProperty("jdbc.url"),
prop.getProperty("jdbc.user"),
prop.getProperty("jdbc.password")
);
state = conn.createStatement();
rs = state.executeQuery(prop.getProperty("jdbc.reload.sql"));
while(rs.next()){
String theWord = rs.getString("word");
logger.info("[--------]hot word from mysql: " + theWord);
_MainDict.fillSegment(theWord.trim().toCharArray());
}
Thread.sleep(Integer.valueOf(String.valueOf(prop.get("jdbc.reload.interval"))));
}catch (Exception e){
logger.error("error",e);
}finally {
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
logger.error("error",e);
}
}
if(state != null){
try {
state.close();
} catch (SQLException e) {
logger.error("error",e);
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
logger.error("error",e);
}
}
}
}
- 8)缘回、在Dictionary類新增loadMySQLStopWordDict方法吆视,從mysql中加載停用詞
/**
* 從mysql中加載停用詞
*/
private void loadMySQLStopWordDict(){
Connection conn = null;
Statement state = null;
ResultSet rs = null;
try{
Path file = PathUtils.get(getDictRoot(),"jdbc-reload.properties");
prop.load(new FileInputStream(file.toFile()));
for (Object key : prop.keySet()) {
logger.info("[--------]" + key +"=" + prop.getProperty(String.valueOf(key)));
}
logger.info("[--------]query hot stopword from mysql," + prop.getProperty("jdbc.reload.stopword.sql") + "......");
// 創(chuàng)建數(shù)據(jù)連接
conn = DriverManager.getConnection(
prop.getProperty("jdbc.url"),
prop.getProperty("jdbc.user"),
prop.getProperty("jdbc.password")
);
state = conn.createStatement();
rs = state.executeQuery(prop.getProperty("jdbc.reload.stopword.sql"));
while(rs.next()){
String theWord = rs.getString("word");
logger.info("[--------]hot stopword from mysql: " + theWord);
_MainDict.fillSegment(theWord.trim().toCharArray());
}
Thread.sleep(Integer.valueOf(String.valueOf(prop.get("jdbc.reload.interval"))));
}catch (Exception e){
logger.error("error",e);
}finally {
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
logger.error("error",e);
}
}
if(state != null){
try {
state.close();
} catch (SQLException e) {
logger.error("error",e);
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
logger.error("error",e);
}
}
}
}
3、mvn package打包代碼
4酥宴、解壓ik壓縮包
將mysql驅(qū)動(dòng)jar啦吧,放入ik目錄下。5拙寡、修改jdbc相關(guān)配置
6授滓、重啟es
觀察日志,日志中會(huì)顯示打印那些東西肆糕,比如加載了什么配置般堆,加載了什么詞語(yǔ),加載了什么停用詞诚啃。7淮摔、在MySQL中添加詞庫(kù)與停用詞
8、分詞驗(yàn)證绍申,驗(yàn)證熱更新
總結(jié):
- 一般不需要特別指定查詢時(shí)分詞器噩咪,直接使用索引時(shí)分詞器即可,否則會(huì)出現(xiàn)無法匹配的情況极阅。
- 明確字段是否需要分詞胃碾,不需要分詞的字段就將type設(shè)置為keyword,可以節(jié)省空間和提高寫性能筋搏。
- 善用_analyze API仆百,查看文檔的具體分詞結(jié)果。