2012-12-14 44 views
1

我使用術語「子文檔」鬆散與存儲在集合屬性的對象。鑑於這兩個類:我可以查詢和使用全文搜索檢索集合屬性的成員RavenDB?

public class Foo 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public IList<Bar> Bars { get; set; } 
} 

public class Bar 
{ 
    public string Name { get; set; } 
    public string Description { get; set; } 
    public string SomeString { get; set; } 
    public int SomeInt { get; set; } 
} 

我想查詢其在任其名稱或描述性術語「玫瑰」吧。請注意酒吧存放在Foo內。

這是一個雙重的問題:

  1. 可以查詢被在Foo類型的集合,用於返回酒吧(「子文件」)?我想要獲得一系列名稱中有「玫瑰」的酒吧,其他酒吧應該跳過。我不想要Foos(聚合根)返回。
  2. 如果是這樣,如何使用全文搜索做呢?

關於#1,我知道類似這樣的事情在MongoDB中是不可能的,在那裏我要麼分別存儲Foo和Bar,要麼查詢其中的任何酒吧中的「玫瑰」在名稱中的Foos,然後執行關於客戶端的一些事情。但RavenDB有實時投影/變換結果,所以我想也許可以。

回答

2

您可以在索引存儲場地存儲中存儲每個條的副本,所以是的 - 可以完成。但你應該確保你瞭解這樣做的影響。

正常情況下,當您從烏鴉進行查詢時,索引僅用於確定將哪些文檔發回。文檔本身不是來自索引,而是來自文檔存儲。文檔存儲具有ACID保證 - 這意味着無論索引狀態如何,您都將始終獲得最新的文檔副本。如果您從索引條目或索引字段存儲中進行項目投射,則返回的值與索引本身一樣陳舊。

假設您不斷更新酒吧,並在索引追上最後更新之前進行搜索。你可以找回一個有舊數據的Bar。因此,你需要在數據的潛在陳舊權衡到你的結果,可能使用WaitForNonStaleResultsAsOf...自定義之一 - 如果你有很多寫事的,這將減緩你的搜索結果返回的速度。

public class Foos_BarsByName 
    : AbstractIndexCreationTask<Foo, Foos_BarsByName.Result> 
{ 
    public class Result 
    { 
     public string Name { get; set; } 
     public Bar Bar { get; set; } 
    } 

    public Foos_BarsByName() 
    { 
     Map = foos => from foo in foos 
         from bar in foo.Bars 
         select new 
         { 
          bar.Name, 
          Bar = bar 
         }; 

     Index(x => x.Name, FieldIndexing.Analyzed); 
     Index(x => x.Bar, FieldIndexing.No); 
     Store(x => x.Bar, FieldStorage.Yes); 
    } 
} 

var results = session.Query<Foos_BarsByName.Result, Foos_BarsByName>() 
        .Customize(x => x.WaitForNonStaleResultsAsOfNow()) 
        .Search(x => x.Name, "roses") 
        .Select(x => x.Bar); 

處理它的另一種方法可能是讓所有的Foos回來,然後在客戶端拉出您感興趣的酒吧。至少這樣,一切都從文檔存儲:

public class Foos_BarsByName 
    : AbstractIndexCreationTask<Foo, Foos_BarsByName.Result> 
{ 
    public class Result 
    { 
     public string Name { get; set; } 
    } 

    public Foos_BarsByName() 
    { 
     Map = foos => from foo in foos 
         from bar in foo.Bars 
         select new 
         { 
          bar.Name 
         }; 

     Index(x => x.Name, FieldIndexing.Analyzed); 
    } 
} 

var results = session.Query<Foos_BarsByName.Result, Foos_BarsByName>() 
        .Search(x => x.Name, "roses") 
        .As<Foo>() 
        .AsEnumerable() 
        .SelectMany(x => x.Bars) 
        .Where(x => x.Name.IndexOf("roses", 
            StringComparison.CurrentCultureIgnoreCase) 
            != -1) 

.AsEnumerable()將迫使LINQ到烏鴉查詢來執行,使得隨後發生的一切LINQ到物體上的客戶端。

當然,如果您正在進行比c#字符串函數更高級的搜索,那麼您將無法採用第二種方法。

+0

我不認爲我需要關心我需要做的陳舊結果。如果用戶等待一小段時間添加/編輯將其添加到搜索結果中,則可以。我會確保顯示通知。 事實證明,我實際上需要構建一個複合結構,其中有一些來自Foo的字段和一些來自Bar的字段,但方法是相同的。你幫了我很多,馬特,我爲此感謝你! –