搜索两个Lucene-Documents

时间:2016-05-17 19:37:01

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

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

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

现在,我可以搜索像

这样的Dash-Entries
+Description:"Appointment" +Username:"mm"

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

现在,我必须在两个文档上搜索Dash-Entries。例如,我必须搜索用户名" mm"的所有Dash条目。并有字符串"约会"在描述或相关的活动实体中有"约会"在主题中。在SQL(Pseudo)中,这将是:

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

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

1 个答案:

答案 0 :(得分:0)

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

如果你搜索“id:1”,你怎么知道你是否检索过Dash或者一个活动?

或者:

  • 确保字段名称是唯一的,即“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");
    }
}

这只是写在我的头顶,所以道歉,如果它不太正确:))

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

另一个选项

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

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

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

祝你好运:)