【问题标题】:Search over two Lucene-Documents搜索两个 Lucene 文档
【发布时间】:2016-05-17 19:37:00
【问题描述】:

我在我的项目中使用 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; }
}

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

现在,我可以搜索 Dash-Entries 之类的

+Description:"Appointment" +Username:"mm"

或像

这样的活动条目
+Subject:"Appointment-Invitation"

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

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

有人可以帮助我吗,我如何使用 Lucene.NET 做到这一点?也许我必须以另一种方式将文档存储在 Lucene.NET-Index 中?

【问题讨论】:

  • 您可以使用 ANDOR 运算符。用户名:mm AND(描述:约会 OR 主题:约会)
  • 但用户名和主题在 Lucene.NET 中不是同一个文档。这也是这种方式吗?
  • 我不明白你在问什么,但它〜等于你的伪 sql stmt。
  • 在我的伪 sql stmt 中是 Dash 和 Activity 两个不同的表,必须加入

标签: c# lucene full-text-search lucene.net


【解决方案1】:

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

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

要么:

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

至少在当前的 Lucene.net (3.0.3) 中,您不能在单个查询中“加入”

Lucene 是一个文档数据存储,在某些方面类似于键值存储。每个文档“只是一堆字段”。

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

但是,您可以通过两个查询和一个“同步枚举”来做一些相当不错的事情。警告:很难说出“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活动,然后将破折号枚举器向前推进以与活动保持同步。假设您将属性值存储在Store.YES 字段中。这种方法只获取id 字段,直到我们找到匹配项,然后投影整个对象。

另一种选择

是将 Lucene 视为“文档数据存储”。创建一个模拟父子的类。所以 Activity 有一个属性是 Dash 的集合。

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

如果更新频率较低,则此方法有效,因为您需要更新整个对象,而不是仅添加单个 Dash 并依赖连接。

祝你好运:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-06
    • 1970-01-01
    • 1970-01-01
    • 2011-10-07
    • 1970-01-01
    • 2015-08-04
    • 1970-01-01
    相关资源
    最近更新 更多