搜索两个 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 并依赖于连接。
祝你好运:)
我在我的项目中使用 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 并依赖于连接。
祝你好运:)