[求助]Lucene多字段索引的创建和查询问题

beimyy 2015-10-13 06:03:29
首先Lucene版本是4.6.1,jdk6支持的最高版本。

项目要对客户数据进行索引,字段有3个,分别是客户名称name、客户名称拼音pinyin、客户简介desc,要求查询返回ID即可。
(先不要吐槽我们有多少客户及是否需要用到Lucene)

我想到的第一个方案是建立一个索引index,每个Document有3个Field,分别对应name、pinyin、desc。
对name字段使用默认分词器StandardAnalyzer即可;
对pinyin字段,需要支持全拼、简拼、全拼简拼混搭,我们自己实现了一个分词器;
对desc字段使用IKAnalyzer。
那么,这时遇到一个问题:
Lucene4.6.1不支持多字段分别使用不同的分词器!!!
(也许是我看api不够仔细没看到这个功能,哪位大牛看到了还望告知一二)

代码如下:

@Test
public void testCreate() throws Exception {

Analyzer nameAnalyzer = new StandardAnalyzer(LuceneUtils.VERSION);
Analyzer pinyinAnalyzer = new PinyinAnalyzer(LuceneUtils.VERSION);
Analyzer ikAnalyzer = new IKAnalyzer();

Directory directory = FSDirectory.open(new File("indexDirectory"));
IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_46, nameAnalyzer);//只能在索引上指定一个analyzer
config.setOpenMode(OpenMode.CREATE);

IndexWriter indexWriter = new IndexWriter(directory, config);
int _id = 1;
String _name = "张小三";
String _pinyin = "zhang‘xiao’san";
String _desc = "这是一个测试客户张小三";

Document doc = new Document();// 创建文档
doc.add(new StringField("id", _id + "", Store.YES));//我要在哪里用analyzer??
doc.add(new TextField("name", _name, Store.YES));
doc.add(new TextField("pinyin", _pinyin, Store.YES));
doc.add(new TextField("desc", _desc, Store.YES));
indexWriter.addDocument(doc);// 添加文本到索引中

indexWriter.commit();
indexWriter.close();

}



然后我想到了第二个方案:
创建3个索引,索引的内容分别是name,pinyi和desc,分词器使用不同的分词器,代码如下:

private IndexWriter createIndexWriter(String indexPath, Analyzer analyzer) throws Exception{
Directory directory = FSDirectory.open(new File("D:/index"));
IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_46, analyzer);//只能在索引上指定一个analyzer
config.setOpenMode(OpenMode.CREATE);
IndexWriter indexWriter = new IndexWriter(directory, config);
return indexWriter;
}
public void testCreate2(String[][] data) throws Exception {
Analyzer nameAnalyzer = new StandardAnalyzer(LuceneUtils.VERSION);
Analyzer pinyinAnalyzer = new PinyinAnalyzer(LuceneUtils.VERSION);
Analyzer ikAnalyzer = new IKAnalyzer();

IndexWriter nameWriter = createIndexWriter("D:/index/name", nameAnalyzer);
IndexWriter pingyinWriter = createIndexWriter("D:/index/pinyin", pinyinAnalyzer);
IndexWriter descWriter = createIndexWriter("D:/index/desc", ikAnalyzer);

for (int i = 0, len = data.length; i < len; i++) {
Document nameDoc = new Document();// 创建文档
nameDoc.add(new StringField("id", data[i][0], Store.YES));// 我要在哪里用analyzer??
nameDoc.add(new TextField("content", data[i][1], Store.YES));
nameWriter.addDocument(nameDoc);

Document pinyinDoc = new Document();// 创建文档
pinyinDoc.add(new StringField("id", data[i][0], Store.YES));// 我要在哪里用analyzer??
pinyinDoc.add(new TextField("content", data[i][2], Store.YES));
pingyinWriter.addDocument(pinyinDoc);

Document descDoc = new Document();// 创建文档
descDoc.add(new StringField("id", data[i][0], Store.YES));// 我要在哪里用analyzer??
descDoc.add(new TextField("content", data[i][3], Store.YES));
descWriter.addDocument(descDoc);
}
nameWriter.commit();
nameWriter.close();
pingyinWriter.commit();
pingyinWriter.close();
descWriter.commit();
descWriter.close();
}

@Test
public void test2() {
String[][] data = { { "1", "张小三", "zhang'xiao'san", "这是一个测试客户张小三" },
{ "2", "李大四", "li'da'si", "第二个用户大李四" },
{ "3", "张四", "zhang'si", "最后的客户四张" } };

}


索引是创建出来了,但此时又遇到一个问题,我该如何查询呢?
Lucene提供的MultiReader支持查询多个Index,但不能分别指定分词器(我已经醉了),贴代码:

public static IndexReader getReader(String indexPath) throws IOException {
return DirectoryReader.open(FSDirectory.open(new File(indexPath)));// 索引读取类
}

public void show(IndexSearcher searcher, TopDocs topdocs, String... fields) throws IOException {
ScoreDoc[] scoreDoc = topdocs.scoreDocs;
int len = scoreDoc.length;
System.out.println("检索结果 共 : " + len);
for (int i = 0; i < len; i++) {
ScoreDoc sd = scoreDoc[i];
System.out.println("得分 score = " + sd.score);
Document doc = searcher.doc(sd.doc);
for (int k = 0, klen = fields.length; k < klen; k++) {
System.out.println(fields[k] + " === " + doc.get(fields[k]));
}
}
}

@Test
public void query3() throws Exception {
String queryStr = "张三";
IndexReader nameReader = getReader("D:/index/name");
IndexReader pinyinReader = getReader("D:/index/pinyin");
IndexReader descReader = getReader("D:/index/desc");
MultiReader multiReader = new MultiReader(nameReader, pinyinReader, descReader);
IndexSearcher s = new IndexSearcher(multiReader);

Analyzer analyzer = new StandardAnalyzer(LuceneUtils.VERSION);
Analyzer ikanalyzer = new IKAnalyzer();

QueryParser queryParser = new QueryParser(LuceneUtils.VERSION, "content", analyzer);//分词器只能写一个!!
Query query = queryParser.parse(queryStr);
TopDocs topdocs = s.search(query, 10);// 查询前10条
show(s, topdocs, "id", "content");
}


上面两个方案都行不通,请各位大牛顺手指点一二!
不要说“自己写个分词器,同时把name、pinyin、desc三个字段全分了”这种话了,写pinyin分词器都快写死了的人无力啊!
...全文
207 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
shijies 2015-10-22
  • 打赏
  • 举报
回复
http://www.iteye.com/problems/58048 使用范例
shijies 2015-10-22
  • 打赏
  • 举报
回复
http://blog.csdn.net/liuweitoo/article/details/8137415 7.2. 特定域分析 在索引操作期间,对于分析器选择的粒度为 IndexWriter 或文档级别。 如果使用QueryParser,则程序会只用一个分析器来处理文本。 但有时,不同的域要使用不同的分析器来分析。 在程序内部,分析器能轻易地处理正在被处理的域名,因为这个域名是作为参数传入其tokenStream方法的。 Lucene内置的分析器却不能扩展这种能力,因为它被设计用来处理一般情况,而域名则是与应用程序有关的。 不过,可以很容易创建一个自定义分析器来处理这种情况。 作为可选,Lucene的内置工具类 PerFieldAnalyzerWapper,这个类,可以针对每个域使用不同的分析器。 //在创建 PerFieldAnalyzerWapper 时,要提供默认的分析器。 PerFieldAnalyzerWapper analyzer = new PerFieldAnalyzerWapper(new SimpleAnalyzer()); //要使用不同的分析器处理域时,可以调用其addAnalyzer()方法 //其它没有指定的域,则使用默认的分析器 analyzer.addAnalyzer("body", new StandardAnalyzer(Version.LUCENE_30));
shijies 2015-10-19
  • 打赏
  • 举报
回复
lucene有一个内置的工具类PerFieldAnalyzerWapper解决这个问题
  • 打赏
  • 举报
回复
beimyy 2015-10-18
  • 打赏
  • 举报
回复
引用 1 楼 shijing266 的回复:
你写了这么长,我都看头疼了 给你一个参考看看
你这个我看过了, 我的问题在这里:
 Query query = MultiFieldQueryParser.parse(queries, fields, clauses, new StandardAnalyzer());  
MultiFieldQueryParser.parse方法里面的分词器参数是一个对象,我希望fields中不同字段用不同的分词器进行查询。
beimyy 2015-10-18
  • 打赏
  • 举报
回复
引用 3 楼 shijies 的回复:
各字段可以分别使用不同的分析器
请问是通过哪个api?我一直没有找到
shijies 2015-10-16
  • 打赏
  • 举报
回复
各字段可以分别使用不同的分析器
shijies 2015-10-16
  • 打赏
  • 举报
回复
各字段可以分别使用不同的分词器
  • 打赏
  • 举报
回复
你写了这么长,我都看头疼了 给你一个参考看看

67,513

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧