library - ¿Cómo puedo usar PriorityQueue de Lucene cuando no conozco el tamaño máximo en el momento de la creación?
lucene tutorial (2)
La razón por la que la cola de prioridad de Lucene es de tamaño limitado es porque usa una implementación de tamaño fijo que es muy rápida.
Piense en cuál es el número máximo razonable de resultados para obtener a la vez y use ese número; el "desperdicio" para cuando los resultados son pocos no es tan malo por el beneficio que obtiene.
Por otro lado, si tiene una cantidad tan grande de resultados que no puede mantenerlos, ¿cómo los va a mostrar / mostrar? Tenga en cuenta que esto es para éxitos "principales", de modo que a medida que repite los resultados, obtendrá menos y menos relevantes de todos modos.
Creé un recopilador personalizado para Lucene.Net, pero no puedo encontrar la manera de ordenar (o publicar) los resultados. Cuando se llama a Everytime Collect, puedo agregar el resultado a una PriorityQueue interna, que entiendo es la forma correcta de hacerlo.
Extendí PriorityQueue, pero requiere un parámetro de tamaño en la creación. Tienes que llamar a Initialize en el constructor y pasar el tamaño máximo.
Sin embargo, en un recopilador, el buscador solo llama a Collect cuando obtiene un resultado nuevo, por lo que no sé cuántos resultados tengo cuando creo PriorityQueue . Basado en esto, no puedo entender cómo hacer que el PriorityQueue funcione.
Me doy cuenta de que probablemente me esté perdiendo algo simple aquí ...
PriorityQueue no es SortedList
u SortedDictionary
. Es un tipo de implementación de clasificación donde devuelve los mejores resultados M (el tamaño de PriorityQueue) de N elementos. Puede agregar con InsertWithOverflow
tantos elementos como desee, pero solo contendrá los elementos M superiores.
Supongamos que su búsqueda generó 1000000 visitas. ¿Devolverías todos los resultados al usuario? Una mejor manera sería devolver los 10 elementos principales al usuario (usando PriorityQueue(10)
) y si el usuario solicita los siguientes 10 resultados, puede hacer una nueva búsqueda con PriorityQueue(
20
)
y devolver los siguientes 10 elementos y pronto. Este es el truco que utilizan la mayoría de los motores de búsqueda como google.
Everytime Commit gets called, I can add the result to an internal PriorityQueue
.
No puedo entender la relación entre Commit
y la search
. Por lo tanto, añado un uso de muestra de PriorityQueue:
public class CustomQueue : Lucene.Net.Util.PriorityQueue<Document>
{
public CustomQueue(int maxSize): base()
{
Initialize(maxSize);
}
public override bool LessThan(Document a, Document b)
{
//a.GetField("field1")
//b.GetField("field2");
return //compare a & b
}
}
public class MyCollector : Lucene.Net.Search.Collector
{
CustomQueue _queue = null;
IndexReader _currentReader;
public MyCollector(int maxSize)
{
_queue = new CustomQueue(maxSize);
}
public override bool AcceptsDocsOutOfOrder()
{
return true;
}
public override void Collect(int doc)
{
_queue.InsertWithOverflow(_currentReader.Document(doc));
}
public override void SetNextReader(IndexReader reader, int docBase)
{
_currentReader = reader;
}
public override void SetScorer(Scorer scorer)
{
}
}
searcher.Search(query,new MyCollector(10)) //First page.
searcher.Search(query,new MyCollector(20)) //2nd page.
searcher.Search(query,new MyCollector(30)) //3rd page.
EDIT para @nokturnal
public class MyPriorityQueue<TObj, TComp> : Lucene.Net.Util.PriorityQueue<TObj>
where TComp : IComparable<TComp>
{
Func<TObj, TComp> _KeySelector;
public MyPriorityQueue(int size, Func<TObj, TComp> keySelector) : base()
{
_KeySelector = keySelector;
Initialize(size);
}
public override bool LessThan(TObj a, TObj b)
{
return _KeySelector(a).CompareTo(_KeySelector(b)) < 0;
}
public IEnumerable<TObj> Items
{
get
{
int size = Size();
for (int i = 0; i < size; i++)
yield return Pop();
}
}
}
var pq = new MyPriorityQueue<Document, string>(3, doc => doc.GetField("SomeField").StringValue);
foreach (var item in pq.Items)
{
}