文章目录
版本选择:
Lucene 4.10.3+IKAnalyzer2012FF_u1
代码地址:https://gitee.com/fenglifengli/lucene4.git
一、中文分词的选择
个人选择:IKAnalyzer
分词器 | 说明 |
---|---|
jcseg中文分词器 | 听说分词准确率高达98.4%,持中文人名识别, 同义词匹配。但是我搞了半天都似乎和lucene4.10.3不兼容 |
IKAnalyzer | 轻量级,还不错 |
PaodingAnalyzer | 庖丁法,这个好像要安装词典 |
ChinesAnalyzer | 只能进行单字分析 |
二、索引创建、查询、更新、删除
问题描述:就是给一个标签库,在给一个输入字符串。对输入字符串进行中文划分产生查询条件,在标签库中查找满足条件的所有标签。
2.1 创建索引
创建索引,索引可以创建到内存中。也可以创建到磁盘上。
/**
* 对创建索引到磁盘和创建索引到内存的整合
* @param marks 标签库
* @param intoRAM 是否将索引建立到内存中
* @return 返回索引的目录
* @throws IOException
*/
public static Directory createIndex(Map<String,String> marks,boolean intoRAM) throws IOException {
Directory directory;
if(intoRAM==true){
//RAMDirectory就是将索引创建到内存中去,当关闭程序时,就将索引清除
directory=new RAMDirectory();
}else {
//获取当前项目的路径
String relativelyPath=System.getProperty("user.dir");
//下面分隔符要看是部署到那种系统中决定
File indexDir = new File(relativelyPath+"/luceneIndex");
directory=FSDirectory.open(indexDir);
}
//Analyzer analyzer= new ChineseAnalyzer();//单字分词
Analyzer analyzer=new IKAnalyzer();
//Analyzer analyzer=new PaodingAnalyzer();//这个好像要安装词典
//Analyzer analyzer=new CJKAnalyzer(Version.LUCENE_4_10_3);//二元分词
IndexWriterConfig writerConfig = new IndexWriterConfig(Version.LUCENE_4_10_3, analyzer);
IndexWriter indexWriter = new IndexWriter(directory, writerConfig);
//删除索引
indexWriter.deleteAll();
for(String key:marks.keySet()){
Document document=new Document();
document.add(new Field("label",marks.get(key), TextField.TYPE_STORED));
document.add(new Field("id",key, TextField.TYPE_STORED));
indexWriter.addDocument(document);
}
indexWriter.close();
return directory;
}
2.2 查询
- 首先,我们将输入字符串进行中文划分,选择的是IKAnalyzer
/**
* 使用指定的分词器对输入进行中文分词
* @param input 输入字符
* @param analyzer 分析器(单字分析用ChineseAnalyzer,其它可以选择IKAnalyzer)
* @return
*/
public static ArrayList<String> getQueryArray(String input,Analyzer analyzer){
ArrayList<String> result=new ArrayList<String>();
//Analyzer analyzer= new ChineseAnalyzer();//单字分词
// Analyzer analyzer=new IKAnalyzer();
//Analyzer analyzer=new PaodingAnalyzer();//这个好像要安装词典
//Analyzer analyzer = new IKAnalyzer();
//Analyzer analyzer=new JcsegAnalyzer5X(JcsegTaskConfig.SIMPLE_MODE);//jcseg2.1.0,1.9.9,2.0.1好像和lucene4.10.3不兼容
TokenStream stream = null;
try {
stream = analyzer.tokenStream("myfield", input);
stream.reset();
CharTermAttribute offsetAtt = stream.addAttribute(CharTermAttribute.class);
while (stream.incrementToken()) {
//System.out.println(offsetAtt.toString());
result.add(offsetAtt.toString());
}
stream.end();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
stream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return result;
}
该方法是使用IKAnalyzer(当然,也可以选择兼容的分词器)对字符串进行分词
测试代码:
@Test
public void getQueryArrayTest(){
ChineseAnalyzer chineseAnalyzer=new ChineseAnalyzer();
StandardAnalyzer standardAnalyzer=new StandardAnalyzer(Version.LUCENE_4_10_3);
CJKAnalyzer cjkAnalyzer=new CJKAnalyzer(Version.LUCENE_4_10_3);
IKAnalyzer ikAnalyzer=new IKAnalyzer();
ArrayList<String> querys= IndexManagerUtils.getQueryArray("IndexReader和IndexWriter都由删除索引的功能,但这两者是有区别的",ikAnalyzer);
for(int i=0;i<querys.size();++i){
System.out.println(querys.get(i));
}
}
分词结果:
indexreader
和
indexwriter
都由
删除
索引
的
功能
但
这两者
两者
两
者
是
有
区别
别的
的
- 组合查询(以“或”的形式)
/**
* 根据所给索引目录与条件查询结果
* @param conditions 多组条件
* @param directory 索引的目录
* @return
*/
public static Map<String,String> searchByConditions(ArrayList<String> conditions,Directory directory) throws IOException {
DirectoryReader ireader = DirectoryReader.open(directory);
IndexSearcher searcher = new IndexSearcher(ireader);
BooleanQuery booleanQuery = new BooleanQuery();
for(int i=0;i<conditions.size();++i){
Term term=new Term("label",conditions.get(i));
TermQuery termQuery=new TermQuery(term);
booleanQuery.add(termQuery, BooleanClause.Occur.SHOULD);
}
ScoreDoc[] scoreDocs = searcher.search(booleanQuery,null, 1000).scoreDocs;
Map<String, String> result = getResultMapByScoreDoc(searcher, scoreDocs);
return result;
}
/**
* 从查询结果scoreDocs中生成Map
* @param searcher
* @param scoreDocs
* @return
* @throws IOException
*/
private static Map<String, String> getResultMapByScoreDoc(IndexSearcher searcher, ScoreDoc[] scoreDocs) throws IOException {
Map<String,String> result=new HashMap<String, String>();
for(int i=0;i<scoreDocs.length;++i){
Document hit = searcher.doc(scoreDocs[i].doc);//doc是一个整数,应该存到是和文档在索引中位置有关的信息吧
result.put(hit.getField("id").stringValue(),hit.getField("label").stringValue());
}
return result;
}
2.3 更新索引,是以IndexWriter进行更新的,要记得close,不然不会更新。如果索引中没有需要更新的文档,那么会将文档add到索引中去。
//根据id更新索引
public static void updateIndex(Map<String,String> someMarks) throws IOException {
//创建IKAnaylzer
Analyzer analyzer=new IKAnalyzer();
//先更新ikDirectory
IndexWriterConfig writerConfig = new IndexWriterConfig(Version.LUCENE_4_10_3, analyzer);
IndexWriter indexWriter = new IndexWriter(ikDirectory, writerConfig);
for(String key:someMarks.keySet()){
Document document=new Document();
document.add(new Field("label",someMarks.get(key), TextField.TYPE_STORED));
document.add(new Field("id",key,TextField.TYPE_STORED));
Term term=new Term("id",key);
indexWriter.updateDocument(term,document);
}
indexWriter.close();
//再更新chDirectory
analyzer=new ChineseAnalyzer();
writerConfig=new IndexWriterConfig(Version.LUCENE_4_10_3,analyzer);
indexWriter=new IndexWriter(chDirectory,writerConfig);
for(String key:someMarks.keySet()){
Document document=new Document();
document.add(new Field("label",someMarks.get(key), TextField.TYPE_STORED));
document.add(new Field("id",key,TextField.TYPE_STORED));
Term term=new Term("id",key);
indexWriter.updateDocument(term,document);
}
indexWriter.close();//注意这里
}
2.4 删除索引,使用IndexWriter的deleteAll方法,并且注意close.
//完全删除索引
public static void deleteIndex() throws IOException {
Analyzer analyzer=new IKAnalyzer();
IndexWriterConfig writerConfig = new IndexWriterConfig(Version.LUCENE_4_10_3, analyzer);
IndexWriter indexWriter = new IndexWriter(ikDirectory, writerConfig);
//删除索引
indexWriter.deleteAll();
indexWriter.close();
analyzer=new ChineseAnalyzer();
writerConfig = new IndexWriterConfig(Version.LUCENE_4_10_3, analyzer);
indexWriter = new IndexWriter(chDirectory, writerConfig);
//删除索引
indexWriter.deleteAll();
indexWriter.close();
}
参考文献
Lucene的各中文分词比较
lucene7.1.0 (二) helloworld
lucene4.10.3入门教程
Lucene 中文分词器 Ik-Analyzer 使用教程
lucene利用BooleanQuery进行多个Query组合查询
Lucene之模糊、精确、匹配、范围、多条件查询-yellowcong
获取java项目根目录
lucene的中文分词器jcseg和IK Analyzer分词器及其使用说明
lucene索引的更新和删除