我正在使用Grails的可搜索插件(它为Compass提供API,它本身就是Lucene的API)。我有一个我想要搜索的Order类,但是,我不想搜索Order的所有实例,只是它们的一部分。像这样:
// This is a Hibernate/GORM call
List<Order> searchableOrders = Customer.findAllByName("Bob").orders
// Now search only these orders with the searchable plugin - something like
searchableOrders.search("name: foo")
实际上,获取searchableOrders的关系查询比这更复杂,所以我无法单独在罗盘中完成整个查询(Hibernate +指南针)。有没有办法使用Compass / Lucene搜索特定类的实例主题。
答案 0 :(得分:4)
一种方法是使用自定义过滤器。例如,如果要根据域类的ID进行过滤,则应将id添加到域类的可搜索配置中:
static searchable = {
id name: "id"
}
然后你会编写你的自定义过滤器(可以进入[project] / src / java):
import org.apache.lucene.search.Filter;
import java.util.BitSet;
import org.apache.lucene.index.TermDocs;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.IndexReader;
import java.io.IOException;
import java.util.List;
public class IdFilter extends Filter {
private List<String> ids;
public IdFilter(List<String> ids) {
this.ids = ids;
}
public BitSet bits(IndexReader reader) throws IOException {
BitSet bits = new BitSet(reader.maxDoc());
int[] docs = new int[1];
int[] freqs = new int[1];
for( String id : ids ) {
if (id != null) {
TermDocs termDocs = reader.termDocs(new Term("id", id ) );
int count = termDocs.read(docs, freqs);
if (count == 1) {
bits.set(docs[0]);
}
}
}
return bits;
}
}
然后你将过滤器作为参数添加到你的搜索中(确保将Filter类导入其他包中):
def theSearchResult = MyDomainClass.search(
{
must( queryString(params.q) )
},
params,
filter: new IdFilter( [ "1" ] ))
这里我只是创建一个单值为“1”的硬编码列表,但是您可以从数据库,以前的搜索或任何地方检索ID列表。
您可以轻松地抽象我必须在构造函数中使用术语名称的过滤器,然后按照您想要的方式传入“名称”。
答案 1 :(得分:2)
两种方法:
最简单的实现方法是在所有对象上进行两次搜索(一次findAll和搜索),然后找到它们之间的交集。如果您缓存findAll调用的结果,那么您实际上只需要进行一个查询。
更“干净”的方法是确保使用Searchable索引域对象的ID,当您获得findAll结果时,将这些ID传递到搜索查询中,从而限制它。
我不记得我的头脑中的Lucene语法,但你必须做类似的事情
searchableOrders.search("name: foo AND (ID:4 or ID:5 or ID:8 ...)" )
您可能在Lucene中遇到查询大小限制,但我认为有一些设置允许您控制查询长度。