1

我正在使用 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 的关系查询比这更复杂,所以我不能单独在 compass 中完成整个查询(Hibernate + compass)。有没有办法使用 Compass/Lucene 仅搜索特定类的实例的主题。

4

2 回答 2

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;
    }
}

然后,您将过滤器作为搜索的参数(如果过滤器类位于不同的包中,请确保导入过滤器类):

def theSearchResult = MyDomainClass.search( 
{
    must( queryString(params.q) )       
}, 
params,
filter: new IdFilter( [ "1" ] ))

在这里,我只是创建了一个硬编码列表,其中包含单个值“1”,但您可以从数据库、以前的搜索或任何地方检索一个 id 列表。

您可以轻松地抽象过滤器,我必须在构造函数中获取术语名称,然后像您想要的那样传入“名称”。

于 2010-01-27T14:21:05.503 回答
2

这样做的两种方法:

从实现的立场来看,最简单的方法是对所有对象进行两次搜索(一次 findAll 和 search),然后找到它们之间的交集。如果您缓存 findAll 调用的结果,那么您实际上只需要进行一个查询。

一种更“干净”的方法是确保使用 Searchable 为域对象的 ID 编制索引,并且当您获得 findAll 结果时,将这些 ID 传递到搜索查询中,从而限制它。

我不记得我脑海中的Lucene语法,但你必须做类似的事情

searchableOrders.search("name: foo AND (ID:4 or ID:5 or ID:8 ...)" )

您可能会在 Lucene 中遇到查询大小限制,但我认为有一些设置可以让您控制查询长度。

于 2009-11-27T20:19:07.603 回答