solr实现动态加载分词
版本是5.3.0
在core(自己创建的模块)的schema.xml里面增加类型:
<fieldType name="text_lj" class="solr.TextField" positionIncrementGap="100" >
<analyzer type="index" >
<tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="false" conf="ik.conf"/> //同级目录下创建的ik.conf文件
</analyzer> <analyzer type="query">
<tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="false" conf="ik.conf"/> //IKTokenizerFactory,这个是我们后面要改造的类
</analyzer> </fieldType>
<field name="desc" type="text_lj" indexed="true" stored="true" required="true" multiValued="false"/>
ik.conf:
lastupdate=1
files=extDic.txt
lastupdate:表示的是版本,比如我现在添加了新的分词,则将版本号加1。files表示分词的文件,后面可以是多个文件名,用英文的逗号分隔。在同级目录下创建文件extDic.txt
extDic.txt的内容:文件保存格式必须是utf-8
小红帽
华为手机
格力空调
给出一个目录:
配置已经完成,现在最主要的是修改ik分词器的源码,主要的思路是创建一个线程轮询更新分词
源码下载地址:https://codeload.github.com/EugenePig/ik-analyzer-solr5/zip/master
使用ideal打开工程:
主要设计这三个类:UpdateKeeper是新创建的,用于轮询读取配置文件
package org.wltea.analyzer.lucene; import java.io.IOException;
import java.util.Vector; //TODO optimize
public class UpdateKeeper implements Runnable{ public static interface UpdateJob{
public void update() throws IOException ; } final static int INTERVAL = 1 * 60 * 1000; private static UpdateKeeper singleton;
Vector<UpdateJob> filterFactorys;
Thread worker; private UpdateKeeper(){
filterFactorys = new Vector<UpdateJob>(); worker = new Thread(this);
worker.setDaemon(true);
worker.start();
} public static UpdateKeeper getInstance(){
if(singleton == null){
synchronized(UpdateKeeper.class){
if(singleton == null){
singleton = new UpdateKeeper();
return singleton;
}
}
}
return singleton;
} /*保留各个FilterFactory实例对象的引用,用于后期更新操作*/
public void register(UpdateKeeper.UpdateJob filterFactory ){
filterFactorys.add(filterFactory);
} @Override
public void run() {
while(true){
try {
Thread.sleep(INTERVAL);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(!filterFactorys.isEmpty()){
for(UpdateJob factory: filterFactorys){
try {
factory.update();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
} }
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.wltea.analyzer.lucene; import java.io.IOException;
import java.io.InputStream;
import java.util.*; import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.util.ResourceLoader;
import org.apache.lucene.analysis.util.ResourceLoaderAware;
import org.apache.lucene.analysis.util.TokenizerFactory;
import org.apache.lucene.util.AttributeFactory;
import org.wltea.analyzer.dic.Dictionary; /**
* @author <a href="mailto:su.eugene@gmail.com">Eugene Su</a>
*/
public class IKTokenizerFactory extends TokenizerFactory implements
ResourceLoaderAware, UpdateKeeper.UpdateJob{
private boolean useSmart; private ResourceLoader loader; private long lastUpdateTime = -1;
private String conf = null; public boolean useSmart() {
return useSmart;
} public void setUseSmart(boolean useSmart) {
this.useSmart = useSmart;
} public IKTokenizerFactory(Map<String,String> args) {
super(args);
String useSmartArg = args.get("useSmart");
this.setUseSmart(useSmartArg != null ? Boolean.parseBoolean(useSmartArg) : false);
conf = get(args, "conf");
} @Override
public Tokenizer create(AttributeFactory factory) {
Tokenizer _IKTokenizer = new IKTokenizer(factory , this.useSmart);
return _IKTokenizer;
} @Override
public void update() throws IOException {
Properties p = canUpdate();
if (p != null){
List<String> dicPaths = SplitFileNames(p.getProperty("files"));
List<InputStream> inputStreamList = new ArrayList<InputStream>();
for (String path : dicPaths) {
if ((path != null && !path.isEmpty())) {
InputStream is = loader.openResource(path);if (is != null) {
inputStreamList.add(is);
}
}
}
if (!inputStreamList.isEmpty()) {
Dictionary.addDic2MainDic(inputStreamList); // load dic to MainDic
}
}
} @Override
public void inform(ResourceLoader resourceLoader) throws IOException {
System.out.println(":::ik:::inform::::::::::::::::::::::::" + conf);
this.loader = resourceLoader;
this.update();
if(conf != null && !conf.trim().isEmpty())
{
UpdateKeeper.getInstance().register(this);
}
} private Properties canUpdate() { try{
if (conf == null)
return null;
Properties p = new Properties();
InputStream confStream = loader.openResource(conf);
p.load(confStream);
confStream.close();
String lastupdate = p.getProperty("lastupdate", "0");
Long t = new Long(lastupdate); if (t > this.lastUpdateTime){
this.lastUpdateTime = t.longValue();
String paths = p.getProperty("files");
if (paths==null || paths.trim().isEmpty()) // 必须有地址
return null;
System.out.println("loading conf");
return p;
}else{
this.lastUpdateTime = t.longValue();
return null;
}
}catch(Exception e){
System.err.println("IK parsing conf NullPointerException~~~~~" + e.getMessage());
return null;
}
} public static List<String> SplitFileNames(String fileNames) {
if (fileNames == null)
return Collections.<String> emptyList(); List<String> result = new ArrayList<String>();
for (String file : fileNames.split("[,\\s]+")) {
result.add(file);
} return result;
}
}
Dictionary类里面新增方法:
Dictionary是单例模式
public static void addDic2MainDic(List<InputStream> inputStreams){
if(singleton == null)
{
Configuration cfg = DefaultConfig.getInstance();
Dictionary.initial(cfg);
}
for(InputStream is : inputStreams){
//如果找不到扩展的字典,则忽略
if(is == null){
continue;
}
try {
BufferedReader br = new BufferedReader(new InputStreamReader(is , "UTF-8"), 512);
String theWord = null;
do {
theWord = br.readLine();
if (theWord != null && !"".equals(theWord.trim())) {
//加载扩展词典数据到主内存词典中
//System.out.println(theWord);
singleton._MainDict.fillSegment(theWord.trim().toLowerCase().toCharArray());
}
} while (theWord != null); } catch (IOException ioe) {
System.err.println("Extension Dictionary loading exception.");
ioe.printStackTrace(); }finally{
try {
if(is != null){
is.close();
is = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
最后将工程打成jar放到web-inf的lib目录里面。大功告成!
solr实现动态加载分词的更多相关文章
- 中文分词实战——基于jieba动态加载字典和调整词频的电子病历分词
分词是自然语言处理中最基本的一个任务,这篇小文章不介绍相关的理论,而是介绍一个电子病历分词的小实践. 开源的分词工具中,我用过的有jieba.hnlp和stanfordnlp,感觉jieba无论安装和 ...
- js动态加载css和js
之前写了一个工具类点此链接里面含有这段代码,感觉用处挺多,特意提出来 var loadUtil = { /* * 方法说明:[动态加载js文件css文件] * 使用方法:loadUtil.loadjs ...
- geotrellis使用(二十三)动态加载时间序列数据
目录 前言 实现方法 总结 一.前言 今天要介绍的绝对是华丽的干货.比如我们从互联网上下载到了一系列(每天或者月平均等)的MODIS数据,我们怎么能够对比同一区域不同时间的数据情况,采用 ...
- Ext JS 如何动态加载JavaScript创建窗体
JavaScript不需要编译即可运行,这让JavaScript构建的应用程序可以变得很灵活.我们可以根据需要动态从服务器加载JavaScript脚本来创建和控制UI来与用户交互.下面结合Ext JS ...
- Ext动态加载Toolbar
在使用Ext的GridPanel时候,有时候需要面板不用重新加载而去更新Store或者Toolbar,Store的方法有很多,例如官方api给我们提供的Store.load(),Store.reLoa ...
- Android动态加载框架汇总
几种动态加载的比较 1.Tinker 用途:热修复 GitHub地址:https://github.com/Tencent/tinker/ 使用:http://www.jianshu.com/p/f6 ...
- 为不同分辨率单独做样式文件,在页面头部用js判断分辨率后动态加载定义好的样式文件
为不同分辨率单独做样式文件,在页面头部用js判断分辨率后动态加载定义好的样式文件.样式文件命名格式如:forms[_屏幕宽度].css,样式文件中只需重新定义文本框和下拉框的宽度即可. 在包含的头文件 ...
- html中的图像动态加载问题
首先要说明下文档加载完成是什么概念 一个页面http请求访问时,浏览器会将它的html文件内容请求到本地解析,从窗口打开时开始解析这个document,页面初始的html结构和里面的文字等内容加载完成 ...
- 非常郁闷的 .NET中程序集的动态加载
记载这篇文章的原因是我自己遇到了动态加载程序集的问题,而困扰了一天之久. 最终看到了这篇博客:http://www.cnblogs.com/brucebi/archive/2013/05/22/Ass ...
随机推荐
- galera+mycat高可用集群部署
环境描述 10.30.162.29 client 环境描述 10.30.162.29 client 10.30.162.72 mysql1 10.30.162.73 mysql2 10.30.162 ...
- liunx存储管理之基础知识
存储基础知识 ====================================================================================主要知识点: 基本 ...
- Maven项目中使用本地JAR包
<dependency> <groupId>com.TEST</groupId> <artifactId>hm-test</artifactId& ...
- Container&injection
容器(Container)就是组件和底层服务细节之间的接口.在web组件.企业级Bean等能够执行之前,它必须被装配为一个JavaEE模块,并部署在容器上. 在JavaEE5时代通过注解的方式注入(i ...
- Oracle数据库联机重定义讲解及错误处理
1.1. 关键字:联机重定义/SYNC_INTERIM_TABLE/GATHER_TABLE_STATS 1.2. 需求:数据表的清理机制需要优化 离线消息表采用delete的方式定期对过期的数据进行 ...
- SQL Server-执行计划教会我如何创建索引
先说点废话 以前有 DBA 在身边的时候,从来不曾考虑过数据库性能的问题,但是,当一个应用程序从头到脚都由自己完成,而且数据库面对的是接近百万的数据,看着一个页面加载速度像乌龟一样,自己心里真是有种挫 ...
- AIX中PV,VG,LV及FS常用相关命令
1.PV常用相关命令 1)lsdev:列出ODM(Object Data Manager)中的设备. 2)chdev:修改一个AIX设备的属性. 3)mkdev:创建一个AIX设备. 4)chpv:修 ...
- vim 插件 -- omnicppcomplete
omnicppcomplete 插件是基于ctags来实现补全的.所以,要先安装好ctags才可以使用. 下载 https://www.vim.org/scripts/script.php?scrip ...
- fiddler抓取用tomcat来部署的项目接口请求包
Fiddler 是以代理web服务器的形式工作的,它使用代理地址:127.0.0.1,端口:8888. 当Fiddler退出的时候它会自动注销, 这样就不会影响别的程序.关于fiddler这个工具的使 ...
- 防止asp马后门
好多朋友都拿的有webshell吧,基本上都加了密的... 可是,没见到源码,很难测试它到底有没有后门, 指不定给别人打工了... 下面贴种很简单的方法,大家别扔蛋哈 (asp的哦) 在代码的最 ...