NHibernate Search和Lucene对IList的初始索引

时间:2012-05-03 16:00:06

标签: nhibernate search lucene.net

我有一些使用Lucene索引IList的无聊问题,我无法修复。

我的实体包含IList,我将这样的IndexedEmbedded属性应用于:

[ScriptIgnore] //will not serialize
[IndexedEmbedded(Depth = 1, Prefix = "BookAdditionalInfos_"]
public virtual IList<BookAdditionalInfo> BookAdditionalInfos { get; set; }

此外,其他一些属性使用Field属性进行索引:

[Field(Index.Tokenized, Store = Store.Yes)]

在标记实体以进行索引之后,我必须对12百万行进行初始索引(使用批处理)。一切都很完美,直到我开始索引名为BookAdditionalInfos的IList。如果没有这个IndexedEmbedded属性(或者没有索引此IList),一切都会正常,并且每个带有Field属性的属性标记都将被编入索引。

我正在使用Fluent NHibernate。

可能有什么问题?

谢谢

编辑:我也看了http://ayende.com/blog/3992/nhibernate-search,但没有任何结果

问题是:当我尝试索引IList时,索引会永远消失,并且不会将任何内容编入索引。如果没有索引这个IList(或没有指定IndexedEmbedded to IList)索引就可以了,我得到了索引结果。

编辑(初始索引功能):

public void BuildInitialBookSearchIndex()
        {
            FSDirectory directory = null;
            IndexWriter writer = null;

            var type = typeof(Book);

            var info = new DirectoryInfo(GetIndexDirectory());

            //if (info.Exists)
            //{
            //    info.Delete(true);
            //}

            try
            {
                directory = FSDirectory.GetDirectory(Path.Combine(info.FullName, type.Name), true);
                writer = new IndexWriter(directory, new StandardAnalyzer(), true);
            }
            finally
            {
                if (directory != null)
                {
                    directory.Close();
                }

                if (writer != null)
                {
                    writer.Close();
                }
            }

            var fullTextSession = Search.CreateFullTextSession(Session);

            var currentIndex = 0;
            const int batchSize = 5000;

            while (true)
            {
                var entities = Session
                    .CreateCriteria<Book>()
                    .SetFirstResult(currentIndex)
                    .SetMaxResults(batchSize)
                    .List();

                using (var tx = Session.BeginTransaction())
                {
                    foreach (var entity in entities)
                    {
                        fullTextSession.Index(entity);
                    }

                    currentIndex += batchSize;

                    Session.Flush();
                    tx.Commit();
                    Session.Clear();
                }

                if (entities.Count < batchSize)
                    break;
            }
        }

1 个答案:

答案 0 :(得分:0)

在我看来,你有一个经典的N + 1选择问题 - 基本上当你选择你的书时,你也没有选择BookAdditionalInfos,所以NHibernate必须为每个选择发出一个新的选择以及每本书在索引时检索该书的BookAdditionalInfo。 快速解决方法是将您的选择更改为:

   var entities = Session
                .CreateCriteria<Book>()
                .SetFetchMode("BookAdditionalInfos", FetchMode.Eager)
                .SetResultTransformer(Transformers.DistinctRootEntity)
                .SetFirstResult(currentIndex)
                .SetMaxResults(batchSize)
                .List();

现在你的分页可能会遇到其他问题,但是因为它会连接到BookAdditionalInfo表,为你的结果集中的同一个实体提供多行,所以你可能想看看做类似的事情:

   var pagedEntities = DetachedCriteria.For<Book>()
                .SetFirstResult(currentIndex)
                .SetMaxResults(batchSize)
                .SetProjection(Projections.Id());

   var entities = Session
                .CreateCriteria<Book>()
                .Add(Property.ForName("id").In(pagedEntities))
                .SetFetchMode("BookAdditionalInfos", FetchMode.Eager)
                .SetResultTransformer(Transformers.DistinctRootEntity)
                .List();