搜索两个 Lucene 文档

Search over two Lucene-Documents

我在我的项目中使用 Lucene.NET。现在我有一个有点棘手的星座。我有两个实体:

public class Dash {
  public int Id { get; set; }
  public string Description { get; set; }
  public int ActivityId { get; set; }
  public string Username { get; set; }
}

public class Activity {
  public int Id { get; set; }
  public string Subject { get; set; }
}

我将实体 Activity 作为文档存储,将 Dash 作为文档存储在 Lucene-Index 中。

现在,我可以搜索

这样的 Dash 条目
+Description:"Appointment" +Username:"mm"

或 Activity-

之类的条目
+Subject:"Appointment-Invitation"

现在,我必须在两个文档中搜索 Dash-Entries。例如,我必须搜索用户名 "mm" 的所有 Dash-Entries 并且在描述中具有字符串 "Appointment" 或关联的 Activity-Entity 在中具有 "Appointment"主题。在 SQL(伪)中,这将是:

... where Dash.UserName = 'mm' and (Dash.Description like 'Appointment%' or Dash.Activity.Subject like 'Appointment%'

谁能帮帮我,我怎么用 Lucene.NET 做到这一点?也许我必须以另一种方式将文档存储在 Lucene.NET-Index 中?

将不同的实体类型放入同一个索引时要小心

如果您搜索 "id:1",您如何知道您检索到的是 Dash 还是 Activity?

或者:

  • 确保字段名称是唯一的,即 "dash_id"、"activity_id"
  • 添加“_type”字段并添加“_type:dash”或“_type:activity”作为搜索过滤器

你不能在单个查询中完成你的 "join" 至少在当前 Lucene.net (3.0.3)

Lucene 是一个文档数据存储,在某些方面类似于 key-value 存储。每个文档是 "just a bunch of fields".

您可以只查询每个实体,然后使用 Linq 连接两个集合。但这可能效率很低并且占用大量内存。一切都取决于您期望获得多少结果。如果数量很少,那么这可能是最简单的。

但是,您可以使用两个查询和一个 "synchronized enumerable" 来做一些相当不错的事情。警告:很难说 "Dash" 是什么,但查看属性我会假设每个 Activity

有很多 Dash

伪代码

// assuming "query" returns a TopDocs
var dashDocs = query "+dash_username:mm +dash_description:Appointment" sort by "dash_ActivityId"
var activityDocs = query "+dash_username:mm +dash_description:Appointment" sort by "activity_Id"

var dashDocsEnum = dashDocs.ScoreDocs.GetEnumerator()
foreach(var activityDocID in activityDocs.ScoreDocs)
{
    if(dashDocsEnum.Current==null)
        break;

    var activityId = GetId(activityDocId.td, "activity_id");
    var dashActivityId = GetId(dashDocsEnum.Current.td, "dash_activityid");

    if(dashActivityId<activityId)
    {
        // spin Dash forward to catch up with Activity
        while(dashActivityId<activityId)
        {
            if(!dashDocsEnum.MoveNext())
                break;
            dashActivityId = GetId(dashDocsEnum.Current.td, "dash_activityid");
        }
    }

    while(dashActivityId==activityId)
    {
        // at this point we have an Activity and a matched Dash
        var fullActivity = GetActivity(activityDocId.td);
        var fullDashActivity = GetDash(dashDocsEnum.Current.td);

        // do something with Activity and Dash

        if(!dashDocsEnum.MoveNext())
            break;
        dashActivityId = GetId(dashDocsEnum.Current.td, "dash_activityid");
    }
}

那是我脑子里想出来的,如果不太正确,请见谅:)

想法是 foreach 活动,然后向前移动破折号枚举器以与 activity 保持同步。假设您将 属性 值存储在 Store.YES 字段中。这种方法只获取 id 字段,直到找到匹配项,然后投影整个对象。

另一个选项

就是把Lucene当作一个"Document datastore"。创建一个模拟 parent-child 的 class。所以 Activity 有一个 属性 这是 Dash 的集合。

将该对象序列化为二进制字段。添加适当的字段以使用 Store.No 进行搜索。这意味着不需要连接,您可以一次获得整个对象。

如果更新频率较低,这会起作用,因为您需要更新整个对象,而不是仅仅添加一个 Dash 并依赖于连接。

祝你好运:)