Mittlerweile bin ich beim vierten Teil der Serie angelangt und wie im vorherigen Artikel erwähnt, möchte ich diesmal auf die Erstellung des Volltextkatalog eingehen. Vorab muss ich jedoch ein wenig ausholen.

Das gesamte Konzept der lokalen Suche soll sich wie ein permanent verfügbarer Datenspeicher, ähnlich einem DBMS, verhalten. Es soll also der Katalog in einer einzigen Instanz für alle Benutzer zur Verfügung stehen und zwar ab dem Start der Anwendung. Wenn der Katalog einmal erstellt wurde kann er in serialiserter Form auf dem Datenträger gespeichert werden. Deshalb auch die Verwendung des Serializable-Attribut sowohl in der Struktur SiteEntry als auch in der Klasse FulltextCatalog.
Bei einem erneuten Start der Anwendung steht sofort ein Katalog zur Verfügung und parallel dazu wird ein neuer, eventuell aktualisierter, Katalog erstellt und auf dem Datenträger gespeichert. Der eben erstellte Katalog verbleibt als aktuelle Instanz zur Verwendung im Speicher.

 SiteSearch Flowchart

Die zentrale Klasse, welche die gesamte Suche verwaltet, habe ich SiteSearch genannt und nach dem Singleton-Entwurfsmuster implementiert.
Die Klasse wird bereits in der Global.asax der Anwendung in der Methode Application_Start instanziiert. Mit dem Aufruf von BuildCatalog wird der Prozess zur Instanziierung des Katalog wie oben beschrieben in Gang gesetzt und anschließend die Anwendung gestartet.

protected void Application_Start(object sender, EventArgs e)
{
    // Schlüssel Viewers in der Anwendung erzeugen
    Application["Viewers"] = 0;

    // Volltextkatalog für die Suche erstellen
    SiteSearch.Instance.BuildCatalog();
}

Wie im oben dargestellten Diagramm ersichtlich wird der Katalog mit der Methode CreateCatalog, die in einem separaten Thread läuft, erstellt.

public void BuildCatalog()
{
    if (this.fulltextCatalog == null)
    {
        this.fulltextCatalog = new FulltextCatalog();
    }

    // prüfen ob bereits eine Katalogdatei vorhanden ist
    if (File.Exists(SiteSearch.catalogFile))
    {
        // Katalog einlesen
        SiteSearch.LoadCatalog();
    }

    // Katalog neu erzeugen
    ThreadPool.QueueUserWorkItem(
		new WaitCallback(SiteSearch.CreateCatalog));
}

Die private statische Methode CreateCatalog prüft als erstes ob bereits ein Index der Seiten, den ich kurz im zweiten Artikel der Serie behandelt habe, erstellt wurde. Falls kein Index vorhanden ist wird dieser erstellt. Als nächstes wird geprüft ob der aktuelle Katalog bereits Daten enthält. Sollten Daten vorhanden sein, wird der Katalog geleert. Anschließend wird durch den Index iteriert und für jeden Eintrag im Index die entsprechende Seite analysiert und dem Katalog hinzugefügt. Abschließend wird der neu erstellte Katalog auf dem Datenträger gespeichert.

private static void CreateCatalog(object stateInfo)
{
    // prüfen ob der Index Daten enthält
    if (SiteSearch.siteIndex == null)
    {
        // Index neu erzeugen
        SiteSearch.siteIndex = new List<string>();
        SiteSearch.CreateSiteIndex(
			new DirectoryInfo(SiteSearch.webRoot));
    }

    // Wenn der Katalog noch Daten enthält
    if (SiteSearch.Instance.fulltextCatalog.Count > 0)
    {
        // Katalog leeren
        SiteSearch.Instance.fulltextCatalog.Clear();
    }

    // für jeden Eintrag im Index einen Eintrag im Katalog erstellen
    foreach (var site in SiteSearch.siteIndex)
    {

        SiteAnalyzer analyzer = new SiteAnalyzer(
            Utils.GetAbsolutUri(site, SiteSearch.context));
        analyzer.TitleDelimeter = "|";
        analyzer.AnalyzeSite();

        // eine neue Instanz der SiteEntry-Struktur erzeugen
        SiteEntry entry = new SiteEntry();

        // die Felder der Struktur belegen
        entry.PubDate = Utils.LastModified(site);
        entry.Title = analyzer.SiteTitle;
        entry.Content = analyzer.SiteContent;
        entry.Url = analyzer.SiteUrl;

        // die Struktur dem Katalog hinzufügen.
        SiteSearch.Instance.fulltextCatalog.Add(entry);
    }

    // Katalog in Datei sichern
    SiteSearch.SafeCatalog();
}

Wie man in der foreach-Schleife sehen kann, wird die Analyse der jeweiligen Seite von einer Klasse SiteAnalyzer durchgeführt. Dem Konstruktor der Seite wird die URL der zu analysierenden Seite übergeben. Die somit erstellte SiteAnalyzer-Instanz führt nach dem Aufruf von AnalyzeSite die Analyse der Seite durch und belegt die Eigenschaften der Instanz mit den jeweiligen Werten. Diese Werte, z.B.: Titel, Inhalt und das Datum der Erstellung oder letzten Änderung, werden anschließend in einer Instanz der SiteEntry-Struktur gespeichert und der FulltextCatalog-Instanz hinzugefügt.
Wie die Analyse der jeweiligen Seite innerhalb der Klasse SiteAnalyzer von statten geht, werde ich im nächsten Artikel der Serie zeigen.

Technorati-Tags:  |  |  | 

Wenn ihnen der Artikel gefallen hat oder er für sie hilfreich war, bitte "kicken" sie ihn.
kick it on dotnet-kicks.de