Bewertung: 4.9 von 8 Benutzern
klaus_b
Nach dem ich in den beiden vorherigen Artikeln sowohl das grundlegende Konzept als auch einen Ansatz zur Erzeugung eines Index vorgestellt habe, möchte ich mich in diesem Beitrag dem Kernstück der Suche widmen; dem Katalog.
So ein Katalog will mit Daten gefüllt werden; also wird erst einmal ein Objekt benötigt, welches alle relevanten Daten einer Seite aufnimmt. Für den Anfang habe ich folgende Eigenschaften angedacht um eine Seite darzustellen:
- Title. Hält den Titel der jeweiligen Seite, oder die URI falls kein Titel vorhanden ist.
- Url. Die URI der Seite.
- Content. Der Textinhalt der Seite, von sämtlichem HTML bereinigt.
- PubDate. Das Datum der Erstellung oder letzten Änderung der Seite.
- Rank. Ein Wert der die Relevanz der Seite in Relation zum Suchbegriff darstellt.
Natürlich können hier noch diverse andere Felder verwendet werden, wie etwa der Inhalt enthaltener Überschriften in H1 bis H4 Tags. Für den Anfang sollten die vorgeschlagenen Felder jedoch genügen um eine Seite darzustellen.
Nur falls sich jemand wundert; Das Feld Rank kommt für den Katalog erst einmal nicht zum tragen. Allerdings wird die gleiche Struktur auch für die Ausgabe der Suchergebnisse verwendet und dort wird dieses Feld benötigt um die Ergebnisse zu werten.
Umgesetzt habe ich dieses Objekt als eine Struktur, welche die Schnittstellen IComparable<T> und IEquatable<T> implementiert. Hier ein Auszug aus der Implementierung. Ich habe lediglich die relevanten Felder dargestellt. Auf die Darstellung der Methoden von IComparable<T> und IEquatable<T> habe ich verzichtet.
[Serializable, StructLayout(LayoutKind.Sequential)]
public struct SiteEntry : IComparable<SiteEntry>, IEquatable<SiteEntry>
{
#region Fields
/// <summary>
/// Stellt einen leeren Eintrag dar.
/// </summary>
/// <remarks>n/a</remarks>
public static readonly SiteEntry Empty;
/// <summary>
/// Der Textinhalt der Seite.
/// </summary>
/// <remarks>n/a</remarks>
public string Content;
/// <summary>
/// Das Datum der Veröffentlichung oder letzten Änderung.
/// </summary>
/// <remarks>n/a</remarks>
public DateTime PubDate;
/// <summary>
/// Die Relevanz der Seite in Relation zum Suchbegriff.
/// </summary>
/// <remarks>n/a</remarks>
public int Rank;
/// <summary>
/// Der Titel der Seite.
/// </summary>
/// <remarks>n/a</remarks>
public string Title;
/// <summary>
/// Die URL zur Seite.
/// </summary>
/// <remarks>n/a</remarks>
public Uri Url;
#endregion Fields
// hier IComparable<T> und IEquatable<T> implementieren
}
Um die vollständige Implementierung zu zeigen, hier das Klassendiagramm der Struktur SiteEntry:
Der eigentliche Katalog braucht nichts anderes zu sein als ein Container, welcher die einzelnen SiteEntry-Instanzen vorhält und ein Iteration durch die Instanzen unterstützt. Meine Wahl viel auf ein versiegelte Klasse, welche die Schnittestelle IEnumerator<T> implementiert.
/// <summary>
/// Stell den Volltextkatalog zur Suche in einer Webanwendung dar
/// </summary>
/// <remarks>n/a</remarks>
[Serializable]
public sealed class FulltextCatalog : IEnumerator<SiteEntry>
{
// hier die Member der Klasse
}
Intern, zum Verwalten der Einträge, wird eine List<T> , im Diagramm als list<SiteEntry> zu sehen, verwendet. Um auf die List<T> von außen zugreifen zu können, oder besser um sie mit Daten zu füllen, werden die Methoden Add, Clear, Contains, Remove und RemoveAt als öffentliche Methoden zur Verfügung gestellt. Da die intern verwendete List<T> auch Einträge mehrmals zulässt ist die Methode Add so implementiert, dass erst in der internen Liste geprüft wird ob bereits eine Instanz des hinzuzufügenden Objekts vorhanden ist. So wird sichergestellt, dass jeder Seiteneintrag nur einmal in der Liste vorkommt.
Um verschiedene Schleifenmethoden zum durchlaufen der Auflistung abzudecken, werden verschiedene Möglichkeit geboten.
Für den Durchlauf mit einer for-Schleife kann mit der Eigenschaft Count die Anzahl der Elemente im Volltextkatalog bestimmt und via einem Indexer das aktuelle Objekt abgefragt werden.
Für die Verwendung einer foreach-Schleife tragen die Member der implementierten IEnumerator<T>-Schnittstelle Sorge.
Dispose ist lediglich enthalten, weil die Schnittstelle IEnumerator<T> bereits IDisposable mitbringt und die Implementierung der Methode verlangt wird.
Im nächsten Artikel wir dann erläutert, wie der Katalog mit den Daten der Seiten eines Webs gefüllt wird. Auch warum sowohl die Struktur SiteEntry als auch die Klasse FulltextCatalog mit dem Serializable-Attribut maskiert sind wird erklärt werden.
Wenn ihnen der Artikel gefallen hat oder er für sie hilfreich war, bitten "kicken" sie ihn.
