"Перемешивание" набора результатов Lucene Hits - PullRequest
0 голосов
/ 03 октября 2011

У меня есть следующая программа:

    public class Hit
    {
        readonly Hits _hits;
        readonly int _index;

        public Hit(Hits hits, int index)
        {
            this._hits = hits;
            this._index = index;
        }

        public int id { get { return _hits.Id(_index); } }
        public float score { get { return _hits.Score(_index); } }
        public string this[string key] { get { return _hits.Doc(_index).Get(key); } }
    }

    class HitList : IList<Hit>
    {
        protected Hits hits;

        public HitList(Hits hits)
        {
            this.hits = hits;
        }

        #region IList Members
        public int Add(object value) { throw new NotImplementedException(); }
        public void Clear() { throw new NotImplementedException(); }
        public bool Contains(object value) { throw new NotImplementedException(); }
        public int IndexOf(object value) { throw new NotImplementedException(); }
        public void Insert(int index, object value) { throw new NotImplementedException(); }
        public bool IsFixedSize { get { throw new NotImplementedException(); } }
        public bool IsReadOnly { get { throw new NotImplementedException(); } }
        public void Remove(object value) { throw new NotImplementedException(); }
        public void RemoveAt(int index) { throw new NotImplementedException(); }
        public object this[int index] { get { return new Hit(hits, index); } set { throw new NotImplementedException(); } }
        #endregion

        #region ICollection Members
        public void CopyTo(Array array, int index) { throw new NotImplementedException(); }
        public int Count { get { return hits.Length(); } }
        public bool IsSynchronized { get { throw new NotImplementedException(); } }
        public object SyncRoot { get { throw new NotImplementedException(); } }
        #endregion

        #region IEnumerable Members
        public System.Collections.IEnumerator GetEnumerator() { throw new NotImplementedException(); }
        #endregion

        #region IList<Hit> Members
        public int IndexOf(Hit item) { throw new NotImplementedException(); }
        public void Insert(int index, Hit item) { throw new NotImplementedException(); }
        Hit IList<Hit>.this[int index] { get { return new Hit(hits, index); } set { throw new NotImplementedException(); } }
        #endregion

        #region ICollection<Hit> Members
        public void Add(Hit item) { throw new NotImplementedException(); }
        public bool Contains(Hit item) { throw new NotImplementedException(); }
        public void CopyTo(Hit[] array, int arrayIndex) { throw new NotImplementedException(); }
        public bool Remove(Hit item) { throw new NotImplementedException(); }
        #endregion

        #region IEnumerable<Hit> Members
        IEnumerator<Hit> IEnumerable<Hit>.GetEnumerator() { throw new NotImplementedException(); }
        #endregion
    }
    private const string IndexFileLocation = @"C:\Users\Public\Index";
    private IList<Hit> _hits;

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        Lucene.Net.Store.Directory dir = Lucene.Net.Store.FSDirectory.GetDirectory(IndexFileLocation, true);

        Lucene.Net.Analysis.Analyzer analyzer = new Lucene.Net.Analysis.Standard.StandardAnalyzer();
        var indexWriter = new Lucene.Net.Index.IndexWriter(dir, analyzer, true);


        for (var i = 0; i < 10; i++)
        {
            var doc = new Lucene.Net.Documents.Document();
            var fldContent = new Lucene.Net.Documents.Field("content", "test " + i,
                                                             Lucene.Net.Documents.Field.Store.YES,
                                                             Lucene.Net.Documents.Field.Index.TOKENIZED,
                                                             Lucene.Net.Documents.Field.TermVector.YES);
            doc.Add(fldContent);
            indexWriter.AddDocument(doc);
        }
        indexWriter.Optimize();
        indexWriter.Close();

        var searcher = new Lucene.Net.Search.IndexSearcher(dir);
        var searchTerm = new Lucene.Net.Index.Term("content", "test");
        Lucene.Net.Search.Query query = new Lucene.Net.Search.TermQuery(searchTerm);

        Lucene.Net.Search.Hits hits = searcher.Search(query);
        for (var i = 0; i < hits.Length(); i++)
        {
            Document doc = hits.Doc(i);
            string contentValue = doc.Get("content");

            Debug.WriteLine(contentValue);
        }
        HitList h = new HitList(hits);

        h.Shuffle();

        for (var i = 0; i < h.Count; i++)
        {
            var z = (Hit)h[i];
            string contentValue = z.id.ToString();

            Debug.WriteLine(contentValue);
        }
    }
}

public static class SiteItemExtensions
{
    public static void Shuffle<T>(this IList<T> list)
    {
        var rng = new Random();
        int n = list.Count;
        while (n > 1)
        {
            n--;
            int k = rng.Next(n + 1);
            T value = list[k];
            list[k] = list[n];
            list[n] = value;
        }
    }
}

Я пытаюсь «перемешать» результаты, которые я получаю из коллекции Hits.Когда я запускаю эту программу как есть, она взрывается, когда я добираюсь до линии h.Shuffle();.Я понимаю, почему его бомбежка.Это взрыв, потому что он выполняет мой метод расширения Shuffle, когда, в свою очередь, пытается выполнить операцию set со значением массива, а у меня нет реализации набора в строке public object this[int index].

Моя проблемаЯ не могу реализовать набор, потому что свойства Lucene ID и Score доступны только для чтения, что, опять же, имеет смысл, почему Apache сделал их доступными только для чтения.Мой вопрос: как я могу «перемешать» или рандомизировать Хиты, которые я получаю?Любая помощь будет оценена.

Ответы [ 2 ]

4 голосов
/ 03 октября 2011

Могут быть некоторые проблемы с производительностью в рассматриваемом подходе для перестановки результатов поиска.

Во-первых, если я правильно помню, класс Hits выполняет локальное кэширование документов и повторяет поиск для каждых 100 документов.Таким образом, для перечисления всех результатов поиска потребуется поиск "HitCount / 100".

Во-вторых, загрузка документа является одной из самых дорогостоящих частей Lucene.Net.Просто чтобы иметь возможность перемешать, загрузка всех результатов поиска может быть не лучшим выбором.

Я бы предпочел подход "случайного подсчета", как показано ниже:

public class RandomScoreQuery : Lucene.Net.Search.Function.CustomScoreQuery
{
   Random r = new Random((int)(DateTime.Now.Ticks & 0x7fffffff));
   public RandomScoreQuery(Query q): base(q)
   {
   }
   public override float CustomScore(int doc, float subQueryScore, float valSrcScore)
   {
       return r.Next(10000) / 1000.0f; //rand scores between 0-10
   }
} 

Query q1 =  new TermQuery(new Term("content", "test"));
Query q2 = new RandomScoreQuery(q1);
TopDocs td = src.Search(q2, 100);
1 голос
/ 03 октября 2011

Вам нужно скопировать свои попадания в подходящую структуру данных и выполнить там сортировку;основная проблема заключается в том, что тип Hits не предназначен для модификации.

Для перемешивания я считаю, что это должно сработать:

var shuffledHits = hits.Cast<Hit>().OrderBy(h => rng.Next());
...