使用GroupingSearch对搜索结果进行分组
Package org.apache.lucene.search.grouping Description
这个模块可以对Lucene的搜索结果进行分组,指定的单值域被聚集到一起。比如,根据”author“域进行分组,“author”域值相同的的文档分成一个组。
进行分组的时候需要输入一些必要的信息:
1、groupField:根据这个域进行分组。比如,如果你使用“author”域进行分组,那么每一个组里面的书籍都是同一个作者。没有这个域的文档将被分到一个单独的组里面。
2、groupSort:组排序。
3、topNGroups:保留多少组。比如,10表示只保留前10组。
4、groupOffset:对排在前面的哪些分组组进行检索。比如,3表示返回7个组(假设opNGroups等于10)。在分页里面很有用,比如每页只显示5个组。
5、withinGroupSort:组内文档排序。注意:这里和groupSort的区别
6、withingroupOffset:对每一个分组里面的哪些排在前面的文档进行检索。
使用GroupingSearch 对搜索结果分组比较简单
GroupingSearch API文档介绍:
Convenience class to perform grouping in a non distributed environment.
非分布式环境下分组
WARNING: This API is experimental and might change in incompatible ways in the next release.
这里使用的是4.3.1版本
一些重要的方法:
示例代码:
1.先看建索引的代码
public class IndexHelper { private Document document; private Directory directory; private IndexWriter indexWriter; public Directory getDirectory(){ directory=(directory==null)? new RAMDirectory():directory; return directory; } private IndexWriterConfig getConfig() { return new IndexWriterConfig(Version.LUCENE_43, new IKAnalyzer(true)); } private IndexWriter getIndexWriter() { try { return new IndexWriter(getDirectory(), getConfig()); } catch (IOException e) { e.printStackTrace(); return null; } } public IndexSearcher getIndexSearcher() throws IOException { return new IndexSearcher(DirectoryReader.open(getDirectory())); } /** * Create index for group test * @param author * @param content */ public void createIndexForGroup(int id,String author,String content) { indexWriter = getIndexWriter(); document = new Document(); document.add(new IntField("id",id, Field.Store.YES)); document.add(new StringField("author", author, Field.Store.YES)); document.add(new TextField("content", content, Field.Store.YES)); try { indexWriter.addDocument(document); indexWriter.commit(); indexWriter.close(); } catch (IOException e) { e.printStackTrace(); } } }
2.分组:
public class GroupTest public void group(IndexSearcher indexSearcher,String groupField,String content) throws IOException, ParseException { GroupingSearch groupingSearch = new GroupingSearch(groupField); groupingSearch.setGroupSort(new Sort(SortField.FIELD_SCORE)); groupingSearch.setFillSortFields(true); groupingSearch.setCachingInMB(4.0, true); groupingSearch.setAllGroups(true); //groupingSearch.setAllGroupHeads(true); groupingSearch.setGroupDocsLimit(10); QueryParser parser = new QueryParser(Version.LUCENE_43, "content", new IKAnalyzer(true)); Query query = parser.parse(content); TopGroups<BytesRef> result = groupingSearch.search(indexSearcher, query, 0, 1000); System.out.println("搜索命中数:" + result.totalHitCount); System.out.println("搜索结果分组数:" + result.groups.length); Document document; for (GroupDocs<BytesRef> groupDocs : result.groups) { System.out.println("分组:" + groupDocs.groupValue.utf8ToString()); System.out.println("组内记录:" + groupDocs.totalHits); //System.out.println("groupDocs.scoreDocs.length:" + groupDocs.scoreDocs.length); for (ScoreDoc scoreDoc : groupDocs.scoreDocs) { System.out.println(indexSearcher.doc(scoreDoc.doc)); } } }
3.简单的测试:
public static void main(String[] args) throws IOException, ParseException { IndexHelper indexHelper = new IndexHelper(); indexHelper.createIndexForGroup(1,"红薯", "开源中国"); indexHelper.createIndexForGroup(2,"红薯", "开源社区"); indexHelper.createIndexForGroup(3,"红薯", "代码设计"); indexHelper.createIndexForGroup(4,"红薯", "设计"); indexHelper.createIndexForGroup(5,"觉先", "Lucene开发"); indexHelper.createIndexForGroup(6,"觉先", "Lucene实战"); indexHelper.createIndexForGroup(7,"觉先", "开源Lucene"); indexHelper.createIndexForGroup(8,"觉先", "开源solr"); indexHelper.createIndexForGroup(9,"散仙", "散仙开源Lucene"); indexHelper.createIndexForGroup(10,"散仙", "散仙开源solr"); indexHelper.createIndexForGroup(11,"散仙", "开源"); GroupTest groupTest = new GroupTest(); groupTest.group(indexHelper.getIndexSearcher(),"author", "开源"); } }
4.测试结果:
两种分页方式
Lucene有两种分页方式:
1、直接对搜索结果进行分页,数据量比较少的时候可以用这种方式,分页代码核心参照:
ScoreDoc[] sd = XXX; // 查询起始记录位置 int begin = pageSize * (currentPage - 1); // 查询终止记录位置 int end = Math.min(begin + pageSize, sd.length); for (int i = begin; i < end && i <totalHits; i++) { //对搜索结果数据进行处理的代码 }
2、使用searchAfter(...)
Lucene提供了五个重载方法,可以根据需要使用
ScoreDoc after:为上次搜索结果ScoreDoc总量减1;
Query query:查询方式
int n:为每次查询返回的结果数,即每页的结果总量
一个简单的使用示例:
//可以使用Map保存必要的搜索结果 Map<String, Object> resultMap = new HashMap<String, Object>(); ScoreDoc after = null; Query query = XX TopDocs td = search.searchAfter(after, query, size); //获取命中数 resultMap.put("num", td.totalHits); ScoreDoc[] sd = td.scoreDocs; for (ScoreDoc scoreDoc : sd) { //经典的搜索结果处理 } //搜索结果ScoreDoc总量减1 after = sd[td.scoreDocs.length - 1]; //保存after用于下次搜索,即下一页开始 resultMap.put("after", after); return resultMap;
我正在努力在我们的应用程序中集成Lucene。Lucene目前正在工作,例如当我搜索“上传”时,文档中有一些叫做“上传”的文本,那么它就工作了,但是当我搜索“上传”时,那么它就不工作了。有什么想法吗? 代码: 谢谢你。
首先,对不起我的英语不好! 我是Lucene图书馆的新人(从上周三开始),我试图了解如何根据找到的术语获得匹配文档的最佳相关性级别。 我使用Lucene 4.10。0(无Solr) 我能够索引/搜索英语/阿拉伯语文本,以及支持这些文本的点击突出显示。 现在我有一个问题与搜索结果的相关性。 如果我在三个文档中搜索“穆罕默德·奥马尔”: 我得到同样的分数为这3文档。 看起来Lucene忽略了单词顺序,
我到处找了又找,但还是找不到解决问题的办法。我还不熟悉php和codeigniter,所以可能我已经错过了答案,但不管怎样,下面是我要做的。 这是我的控制器(c_index.php)-调用搜索函数并对结果数组执行分页。 这是我的视图(index.php)-基本上只是显示分页结果 我的模型(m_search.php)-基本上搜索数据库并返回结果数组。 类M_搜索扩展了CI_模型{ 现在我的问题是保留
我被要求对数组进行排序和搜索。数组的排序很简单,我的代码有效,但是每当我尝试调用二叉搜索方法时,它都适用于数组中的第一个元素,但结果给了我“-1” 我的完整代码如下:
我试图用一个词作为查询来查找匹配项,但它似乎找不到。我正在使用标准分析仪,但找不到准确的结果。 我的索引文档是: 如果使用通配符查询: 它会返回内容:“敏捷的棕色狐狸跳过懒惰的狗” 如果使用术语查询: 它会返回内容:“敏捷的棕色狐狸跳过懒惰的狗” 现在,我想用“狐狸”作为我的新名词 但是我不知道哪个是正确的查询,或者如何做。我已经尝试了QueryParser、TermQuery和MultiPhra
供参考:我的代码和这个so帖子非常相似。 谢谢