<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:blogChannel="http://backend.userland.com/blogChannelModule" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    <title>klaus_b@.NET</title>
    <description>Das private Weblog von Klaus Bock über alles was an .NET und C# Spass macht.</description>
    <link>http://blog.klaus-b.net/</link>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <generator>BlogEngine.NET 1.5.0.9</generator>
    <language>de-DE</language>
    <blogChannel:blogRoll>http://blog.klaus-b.net/opml.axd</blogChannel:blogRoll>
    <blogChannel:blink>http://blog.klaus-b.net/syndication.axd</blogChannel:blink>
    <dc:creator>Klaus Bock</dc:creator>
    <dc:title>klaus_b@.NET</dc:title>
    <geo:lat>48.195000</geo:lat>
    <geo:long>12.389000</geo:long>
    <creativeCommons:license>http://creativecommons.org/licenses/by-sa/2.0/</creativeCommons:license><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/klaus_b" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
      <title>Double Content durch normalisierte URLs</title>
      <description>&lt;p&gt;In letzter Zeit fielen mir bei der Überprüfung meines Blog in den Google &lt;a title="Google Webmaster-Tools" href="http://www.google.com/webmasters/tools/home?hl=de"&gt;Webmaster-Tools&lt;/a&gt; vermehrte Hinweise auf &lt;a title="SEO Lexicon: Double Content" href="http://www.express-submit.de/lexikon/double_content.html"&gt;Double Content&lt;/a&gt; auf. Die Ursache war schnell gefunden. Jede angemahnte Seite war mit zwei URLs vertreten: einmal mit der original URL und einmal mit einer URL komplett in &lt;a title="Kleinschreibung" href="http://de.wikipedia.org/wiki/Kleinschreibung" rel="wiki"&gt;Kleinschreibung&lt;/a&gt;. Für dieses Verhalten konnte nur einer der zahlreichen Bookmark-Dienste verantwortlich sein. Leider konnte ich nicht ermitteln woher die URLs stammten, da die Quelle nicht angezeigt wird. Da die Ursache nicht entfernt werden konnte, muss an der Wirkung gearbeitet werden.&lt;/p&gt;  &lt;p&gt;&lt;a title="ASP.NET" href="http://msdn.microsoft.com/bb400852.aspx" rel="msdn"&gt;ASP.NET&lt;/a&gt; basierende Anwendungen betrachten by Design URLs in unterschiedlicher Schreibweise als gleich. Es macht also keinen Unterschied ob &lt;em&gt;&lt;strong&gt;Das-ist-die-selbe-Seite.aspx&lt;/strong&gt;&lt;/em&gt; oder &lt;em&gt;&lt;strong&gt;das-ist-die-selbe-seite.aspx&lt;/strong&gt;&lt;/em&gt; aufgerufen wird. Es wird beide male die gleiche Seite angezeigt. Dieses Verhalten ist für den Anwender eigentlich nicht schlecht, da er nicht auf Groß- und Kleinschreibung achten muss. Für eine Suchmaschine ist dieses Verhalten jedoch der gleiche Inhalt unter verschiedenen URLs; also Double Content.&lt;/p&gt;  &lt;p&gt;Im Falle meines Blog, der auf &lt;a title="BlogEngine.NET" href="http://www.dotnetblogengine.net/"&gt;Blogengine.NET&lt;/a&gt; basiert, war die Lösung des Problems relativ einfach. Bei der Anforderung einer URL musste ich lediglich die angeforderte URL des jeweiligen Artikel mit der gespeicherten URL aus dem Post-Objekt vergleichen. Sind diese nicht identisch, wird eine permanente Umleitung, Statuscode 301, mit der URL aus dem Post-Objekt an den Client gesendet. Folgende Anpassung ist dabei in der Datei &lt;em&gt;&lt;strong&gt;post.aspx.cs&lt;/strong&gt;&lt;/em&gt; im Wurzelverzeichnis der Anwendung vorzunehmen. Die Zeilennummern im Listing entsprechen dabei den Zeilennummern in der Datei.&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:c9256681-a394-4e7c-b1cf-e45b13233a98" class="wlWriterEditableSmartContent"&gt;&lt;pre title="code" class="c#:firstline[41]"&gt;// verhindert double content durch
// unterschiedliche Schreibweise der URL
string requestUri = this.Request.RawUrl.Substring(
		Request.RawUrl.LastIndexOf('/') + 1);
string postUri = this.Post.RelativeLink.Substring(
		Post.RelativeLink.LastIndexOf('/') + 1);

if (!postUri.Equals(requestUri, StringComparison.Ordinal))
{
    this.Response.Clear();
    this.Response.StatusCode = 301;
    this.Response.AppendHeader(
		"location",
		Post.RelativeLink.ToString());
    this.Response.End();
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Anwender die auch Pages unter Blogengine.NET verwenden, sollten natürlich auch die Datei &lt;strong&gt;&lt;em&gt;page.aspx.cs&lt;/em&gt;&lt;/strong&gt;, ebenfalls im Wurzelverzeichnis zu finden, entsprechend anpassen.&lt;/p&gt;

&lt;p&gt;Die kleine Änderung im Code zeigte Wirkung, denn nach ein paar Tagen waren keine Hinweise mehr auf Double Content in den Google Webmaster-Tools zu finden.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:85293368-91d5-4555-b27b-bad0df8678d8" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/blogengine.net" rel="tag"&gt;blogengine.net&lt;/a&gt;,&lt;a href="http://technorati.com/tags/asp.net" rel="tag"&gt;asp.net&lt;/a&gt;,&lt;a href="http://technorati.com/tags/double+content" rel="tag"&gt;double content&lt;/a&gt;,&lt;a href="http://technorati.com/tags/seo" rel="tag"&gt;seo&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/udjjwjX2MABmnbghhvQHa04eNZc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/udjjwjX2MABmnbghhvQHa04eNZc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/udjjwjX2MABmnbghhvQHa04eNZc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/udjjwjX2MABmnbghhvQHa04eNZc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=t2gaaP-MAS8:QQyJLXAts24:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=t2gaaP-MAS8:QQyJLXAts24:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=t2gaaP-MAS8:QQyJLXAts24:1DmhQM8_AdY"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=1DmhQM8_AdY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/klaus_b/~4/t2gaaP-MAS8" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/t2gaaP-MAS8/post.aspx</link>
      <author>klaus_b0@hotmail.de (klaus_b)</author>
      <comments>http://blog.klaus-b.net/post/2009/11/08/Double-Content-durch-normalisierte-URLs.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=d9610feb-ccff-4be7-ab5d-6b390b44159d</guid>
      <pubDate>Sun, 08 Nov 2009 13:51:46 +0100</pubDate>
      <category>Blogengine.NET</category>
      <dc:publisher>klaus_b0@hotmail.de (klaus_b)</dc:publisher>
      <pingback:server>http://blog.klaus-b.net/pingback.axd</pingback:server>
      <pingback:target>http://blog.klaus-b.net/post.aspx?id=d9610feb-ccff-4be7-ab5d-6b390b44159d</pingback:target>
      <slash:comments>4</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=d9610feb-ccff-4be7-ab5d-6b390b44159d</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2009/11/08/Double-Content-durch-normalisierte-URLs.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=d9610feb-ccff-4be7-ab5d-6b390b44159d</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=d9610feb-ccff-4be7-ab5d-6b390b44159d</feedburner:origLink></item>
    <item>
      <title>Der leidenschaftliche Programmierer</title>
      <description>&lt;p&gt;&lt;a href="http://blog.klaus-b.net/image.axd?picture=book001.gif"&gt;&lt;img style="display: inline" title="Der leidenschaftliche Programmierer" alt="Der leidenschaftliche Programmierer" align="left" src="http://blog.klaus-b.net/image.axd?picture=book001_1.gif" width="100" height="140" /&gt;&lt;/a&gt;lautet der Titel des Buches, welches mir kürzlich in die Hände fiel.     &lt;br /&gt;Chad Fowler, die meisten Ruby-Entwickler dürften ihn kennen, hat mit diesem Buch kein technisches Werk zu einer der vielen Programmiersprachen verfasst, sondern geht viel mehr auf die größeren und kleineren Probleme im Berufsalltag eines Softwareentwicklers ein. In den 53 kurzen, aber sehr prägnanten, Artikeln greift er die verschiedensten Szenarien auf und gibt allerlei Tipps um die ein oder andere Situation zu meistern.     &lt;br /&gt;Man merkt während des Lesens sehr schnell, dass Chad Fowler auf einen reichen Erfahrungsschatz zurückgreifen kann. Da Chad Fowler eigentlich Musiker ist, zieht er immer wieder Parallelen zu diesem Metier und schafft dabei auf anschauliche Art und Weise Verbindungen die für jeden nachvollziehbar sind. Viele dieser Situationen lassen sich problemlos auf alle möglichen Berufe übertragen, genauso wie der jeweilige Lösungsansatz.&lt;/p&gt;  &lt;p&gt;Erwähnenswert sind auch die zahlreichen Anekdoten aus dem Bekanntenkreis des Autors. Eine davon, die mir persönlich am besten gefiel, ist die Schilderung von Tom Preston-Werner wie er ein sehr lukratives Angebot von Microsoft ausschlug um mit GitHub “etwas cooles zu tun”. Der Titel der Anekdote könnte passender nicht sein:    &lt;br /&gt;&lt;em&gt;Wie ich 300.000$ von Microsoft ablehnte, um in Vollzeit an GitHub zu arbeiten&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;So unterhaltsam wie teilweise die enthaltenen Anekdoten sind, so aussagekräftig sind die Titel der einzelnen Kapitel gehalten. Wie etwa der Titel des ersten Kapitel der da lautet: &lt;em&gt;Führen oder bluten?&lt;/em&gt; Der Autor verdeutlicht in diesem ersten Artikel an zahlreichen Beispielen die noch heutige Gültigkeit des alten Leitsatz: “Geringes Risiko. Geringe Belohnung.”&lt;/p&gt;  &lt;p&gt;Das Buch liest sich sehr leicht und unterhaltsam, ist dabei jedoch keineswegs als leichte Unterhaltung zu verstehen. Vielmehr versucht der Autor dem Leser die Augen zu öffnen und die Aufmerksamkeit auf die eigene persönliche Entwicklung des Lesers zu lenken. Er zeigt interessante Betrachtungsweisen ungeliebter Aufgaben und schafft dabei neue Perspektiven. Anhand anschaulicher Beispiele werden Möglichkeiten gezeigt, die der ein oder andere so für sich noch nicht in Betracht gezogen haben mag. Wie der Titel schon erahnen lässt, versucht Chad Fowler den leidenschaftlichen Programmierer im Softwareentwickler zu wecken.&lt;/p&gt;  &lt;p&gt;Meine Leidenschaft für das Programmieren bedurfte keines Erweckens, denn sie ist nie erlöschen. Vieleicht auch, weil ich nie den Zwängen eines professionellen Entwicklers unterworfen war. Ich musste mich nie mit Deadlines und unmöglichen Kundenwünschen herumschlagen.    &lt;br /&gt;Der Autor, der ja selbst Entwickler ist, kennt das Entwicklergeschäft allerdings sehr gut. Ich kann mir gut vorstellen, dass es bestimmt Entwickler da draußen gibt, deren Leidenschaft für ihren Job sanft entschlafen ist; oder der ein oder andere nur noch Code schreibt, damit “Belag auf die Pizza” kommt. Alle die sich jetzt angesprochen fühlen, sollte einmal einen Blick in dieses Buch riskieren.&lt;/p&gt;  &lt;p&gt;Auch alle anderen, deren Neugier geweckt wurde, können sich einen eigenen Eindruck bei einer Leseprobe unter &lt;a href="http://www.it-fachportal.de/5885"&gt;http://www.it-fachportal.de/5885&lt;/a&gt; verschaffen.     &lt;br /&gt;Mir hat es sehr viel Spaß bereitet das Buch zu lesen, konnte aber auch den ein oder anderen Rat mitnehmen.&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:e9e32a1a-8fbb-4ef3-9493-9668e0575d9b" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/books" rel="tag"&gt;books&lt;/a&gt;,&lt;a href="http://technorati.com/tags/review" rel="tag"&gt;review&lt;/a&gt;,&lt;a href="http://technorati.com/tags/the+passionate+programmer" rel="tag"&gt;the passionate programmer&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/nQDBJhgbDcOUKYI-JfC7emXO5IM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/nQDBJhgbDcOUKYI-JfC7emXO5IM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/nQDBJhgbDcOUKYI-JfC7emXO5IM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/nQDBJhgbDcOUKYI-JfC7emXO5IM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=harPNZTqedE:x4YvAFXMLak:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=harPNZTqedE:x4YvAFXMLak:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=harPNZTqedE:x4YvAFXMLak:1DmhQM8_AdY"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=1DmhQM8_AdY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/klaus_b/~4/harPNZTqedE" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/harPNZTqedE/post.aspx</link>
      <author>klaus_b0@hotmail.de (klaus_b)</author>
      <comments>http://blog.klaus-b.net/post/2009/11/07/Der-leidenschaftliche-Programmierer.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=19e49ffe-fa52-43a1-95c8-b9c1535278fc</guid>
      <pubDate>Sat, 07 Nov 2009 17:10:49 +0100</pubDate>
      <category>Allgemeines</category>
      <dc:publisher>klaus_b0@hotmail.de (klaus_b)</dc:publisher>
      <pingback:server>http://blog.klaus-b.net/pingback.axd</pingback:server>
      <pingback:target>http://blog.klaus-b.net/post.aspx?id=19e49ffe-fa52-43a1-95c8-b9c1535278fc</pingback:target>
      <slash:comments>3</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=19e49ffe-fa52-43a1-95c8-b9c1535278fc</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2009/11/07/Der-leidenschaftliche-Programmierer.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=19e49ffe-fa52-43a1-95c8-b9c1535278fc</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=19e49ffe-fa52-43a1-95c8-b9c1535278fc</feedburner:origLink></item>
    <item>
      <title>Rückblick: Erster Intel Blogger Day</title>
      <description>&lt;p&gt;Am 21. Oktober fand in München am Nockherberg der erste Intel B(logger) Day statt. Organisiert wurde das Event von &lt;a title="Intel Deutschland" href="http://www.intel.de/"&gt;Intel&lt;/a&gt; und &lt;a title="Michael Hülskötter bei contentXperten" href="http://www.contentxperten.de/about/"&gt;Michael Hülskötter&lt;/a&gt;, der auch das &lt;a title="Software Dev Blog. Multicore-Programmierung für optimal skalierende Anwendungen." href="http://www.software-dev-blog.de/"&gt;Software Dev Blog&lt;/a&gt; für Intel betreibt.&lt;/p&gt;  &lt;p&gt;Das Event war absolut keine Werbe- oder Verkaufsveranstaltung von Intel, sondern ein sehr interessanter und vor allem informativer runder Tisch um einmal die verschiedene Seiten der Multicore-Unterstützung bzw. Parallel-Programmierung zu beleuchten.&lt;/p&gt;  &lt;p&gt;An erster Stelle, und aus meiner Sicht sehr positiv, fiel mir die &lt;a title=".NET Framework" href="http://de.wikipedia.org/wiki/.NET_Framework" rel="wiki"&gt;.NET&lt;/a&gt; Lastigkeit der Veranstaltung auf, die sich auch in der Liste der Teilnehmer wiederspiegelte.     &lt;br /&gt;Als weiterer Journalist, neben Michael, war auch &lt;a title="Tilman Börner" href="http://twitter.com/dotnetpro_mag"&gt;Tilman&lt;/a&gt; vom &lt;a title="dotnetpro Das Profi-Magazin für Entwickler." href="http://www.dotnetpro.de/"&gt;dotnetpro Magazin&lt;/a&gt; dabei. Dann waren da noch &lt;a title="Dariusz Parys" href="http://blogs.msdn.com/dparys/"&gt;Dariusz&lt;/a&gt; von &lt;a title="Microsoft Deutschland GmbH" href="http://www.microsoft.com/de/de/default.aspx"&gt;Microsoft Deutschland&lt;/a&gt;, sowie &lt;a title="Der-Albert.com sein Blog" href="http://der-albert.com/"&gt;Albert&lt;/a&gt; und meine Wenigkeit als Vertreter der deutschen .NET Blogosphäre. Leider konnten &lt;a title="Lars Keller ...inspired by .NET" href="http://blog.lars-keller.net/"&gt;Lars&lt;/a&gt;, &lt;a title="DotNet-Blog.Net" href="http://www.dotnet-blog.net/"&gt;Gregor&lt;/a&gt; und &lt;a title="Rene Schulte - .NET Software Development" href="http://rene-schulte.info/" jquery1256985783018="8521"&gt;Rene&lt;/a&gt; aus nachvollziehbaren Gründen nicht teilnehmen. Vieleicht klappt es ja beim nächsten mal, denn so wie der allgemeine Tenor klang sollte einer Wiederholung der Veranstaltung nichts im Wege stehen.&lt;/p&gt;  &lt;p&gt;Die Begrüßung der Teilnehmer, durch Beatrice Freadrich von Intel, ging noch planmäßig über die Bühne. Doch schon während der Vorstellungsrunde entbrannte bereits die erste Diskussion ob und warum überhaupt parallelisieren.    &lt;br /&gt;Im Laufe des Abends entwickelten sich noch viele weitere hoch interessante Gespräche rund um das Thema Multicore-Unterstützung. Dabei gingen die Meinungen über mögliche Umsetzungen doch sehr weit auseinander. Während die einen eher zu funktionalen Sprachen wie &lt;a title="F-Sharp" href="http://de.wikipedia.org/wiki/F-Sharp" rel="wiki"&gt;F#&lt;/a&gt; tendieren, andere wiederum die Umsetzung komplett vom Compiler übernommen haben wollen, bevorzuge ich hingegen die Verwendung der &lt;a title="Parallel Extension Internals for the .NET Framework" href="http://msdn.microsoft.com/en-us/library/dd882498(VS.100).aspx" rel="msdn"&gt;Parallel Erweiterung&lt;/a&gt; des .&lt;a title=".NET Framework" href="http://msdn.microsoft.com/netframework/" rel="msdn"&gt;NET-Framework&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;So unterschiedlich wie die Meinungen über mögliche Umsetzungen, waren auch die Ansichten zur Notwendigkeit der Unterstützung mehrere Kerne. Auf einen Punkt gebracht schwebte folgende Aussage im Raum: “Parallelisieren ja, aber bitte ohne Mehraufwand”.    &lt;br /&gt;Meiner Meinung nach kann so eine Aussage auf keinen Fall so hingenommen werden. Auf der einen Seite stellen die CPU-Hersteller immer mehr Kerne zur Verfügung und auf der Anwenderseite erwartet der Benutzer die effektive Nutzung seiner Hardware. Der Entwickler, der ja die vorhandene Hardware auch bitte nutzen möge, sagt aber: “Nein, das ist mir zu viel Arbeit”. Diese Aussage ist bewusst übertrieben, doch wenn ich mir den Hype um &lt;a title="Clean Code Developer" href="http://www.clean-code-developer.de/"&gt;CCD&lt;/a&gt; anschaue und die geschilderte Defensive zur Parallelisierung, drängt sich mir die Frage auf: Warum wird so viel Energie in die CCD-Bewegung investiert und das längst überfällige Umdenken hin zur Umstrukturierung der Architekturen auf eine effektive parallele Verarbeitung unterbleibt so gänzlich? Ich habe keine Antwort.     &lt;br /&gt;Man möge mir an dieser Stelle den Vergleich mit CCD vergeben. Doch gerade die CCD-Bewegung zeigt, wie viel Energie aufgewendet werden kann um gesteckte Ziele zu erreichen. Warum also nicht auch ein wenig Kraft in die Parallelisierung stecken?&lt;/p&gt;  &lt;p&gt;Mit Sicherheit stehen hier auch die Hersteller der Entwicklungsumgebungen und diversen Programmiersprachen in der Pflicht, den Prozess des Umdenkens voranzutreiben. Der Mensch ist von Natur aus faul und nimmt im Allgemeinen Neuerungen nur an, wenn sie nicht mit zu großem Aufwand verbunden sind.    &lt;br /&gt;Warten wir also auf die RTM des .NET-Framework 4.0 und Visual Studio 2010. Meine Hoffnung auf eine Richtungsänderung hin zur vermehrten Nutzung der Parallelisierung hat sich noch nicht erschöpft. Denn bekanntlich stirbt die Hoffnung ja zuletzt.&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:30cb4db7-301e-477a-9cf6-f8cfb9f47a5c" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/community" rel="tag"&gt;community&lt;/a&gt;,&lt;a href="http://technorati.com/tags/parallel+computing" rel="tag"&gt;parallel computing&lt;/a&gt;,&lt;a href="http://technorati.com/tags/parallelfx" rel="tag"&gt;parallelfx&lt;/a&gt;&lt;/div&gt;  &lt;div style="margin-top: 10px; height: 15px" class="zemanta-pixie"&gt;&lt;img style="border-bottom-style: none; border-right-style: none; border-top-style: none; float: right; border-left-style: none" class="zemanta-pixie-img" alt="" src="http://img.zemanta.com/pixy.gif?x-id=cc340c38-5bf3-496a-82f2-4d21d2da9c09" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/oHov2d4JrH1jW7VzMok5ZSRH-_U/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/oHov2d4JrH1jW7VzMok5ZSRH-_U/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/oHov2d4JrH1jW7VzMok5ZSRH-_U/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/oHov2d4JrH1jW7VzMok5ZSRH-_U/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=y5MHzykfqsE:B4aVwjOFSJU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=y5MHzykfqsE:B4aVwjOFSJU:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=y5MHzykfqsE:B4aVwjOFSJU:1DmhQM8_AdY"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=1DmhQM8_AdY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/klaus_b/~4/y5MHzykfqsE" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/y5MHzykfqsE/post.aspx</link>
      <author>klaus_b0@hotmail.de (klaus_b)</author>
      <comments>http://blog.klaus-b.net/post/2009/10/31/Ruckblick-Erster-Intel-Blogger-Day.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=4c93c947-7804-44a0-8043-0e4b14a80319</guid>
      <pubDate>Sat, 31 Oct 2009 14:43:12 +0100</pubDate>
      <category>Community</category>
      <dc:publisher>klaus_b0@hotmail.de (klaus_b)</dc:publisher>
      <pingback:server>http://blog.klaus-b.net/pingback.axd</pingback:server>
      <pingback:target>http://blog.klaus-b.net/post.aspx?id=4c93c947-7804-44a0-8043-0e4b14a80319</pingback:target>
      <slash:comments>8</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=4c93c947-7804-44a0-8043-0e4b14a80319</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2009/10/31/Ruckblick-Erster-Intel-Blogger-Day.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=4c93c947-7804-44a0-8043-0e4b14a80319</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=4c93c947-7804-44a0-8043-0e4b14a80319</feedburner:origLink></item>
    <item>
      <title>Vergleichen von Wörtern mit dem Dice-Koeffizienten</title>
      <description>&lt;p&gt;Wer war nicht schon einmal in der Situation zwei Wörter nicht auf ihre Gleichheit, sondern auf ihre Ähnlichkeit zu prüfen? Wenn ein Kunde nach dem umgangssprachigen Begriff &lt;em&gt;Schraubenzieher&lt;/em&gt; sucht, im Katalog aber nur die korrekte Bezeichnung &lt;em&gt;Schraubendreher&lt;/em&gt; vorhanden ist, stoßen die üblichen Vergleiche an ihre Grenzen.     &lt;br /&gt;Wie soll so ein Vergleich also aussehen?     &lt;br /&gt;Als Ergebnis des Vergleich sollte ein Wert zwischen 0 und 1 zurückgegeben werden. Wobei 0 keine Ähnlichkeit bedeutet und 1 die Wörter sind identisch aussagt.     &lt;br /&gt;Für so einen Vergleich bietet sich entweder der Editierabstand, auch &lt;a title="Levenshrein-Distanz" href="http://de.wikipedia.org/wiki/Levenshtein-Distanz" rel="wiki"&gt;Levenshtein-Distanz&lt;/a&gt; genannt, oder eben der &lt;a title="Dice-Koeffizient" href="http://de.wikipedia.org/wiki/N-Gram#Dice-Koeffizient" rel="wiki"&gt;Dice-Koeffizient&lt;/a&gt; an.     &lt;br /&gt;Der Dice-Koeffizient “d” lässt sich als Definition, wie unter obigem Link in der &lt;a title="Wikipedia" href="http://www.wikipedia.org/" rel="wiki"&gt;Wikipedia&lt;/a&gt; zu sehen, darstellen oder als einfache Bruchrechnung:&lt;/p&gt;  &lt;p align="left"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 2 (Übereinstimmungen aus a und b)    &lt;br /&gt;d(a,b) = ----------------------------------------------------------------     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Anzahl N-Gramme(a) + Anzahl N-Gramme(b)&lt;/p&gt;  &lt;p&gt;Um den Dice-Koeffizienten zweier Wörter zu bestimmen, müssen die einzelnen Wörter erst einmal in N-Gramme zerlegt werden; also in Teilzeichenfolgen der Länge N.    &lt;br /&gt;N mit 1 zu bestimmen währe nicht sehr vorteilhaft, da diese Prüfung einem ordinalen Vergleich entsprechen würde, der bereits im Framework als Member &lt;em&gt;Ordinal&lt;/em&gt; der &lt;a title="StringComparison Enumeration" href="http://msdn.microsoft.com/8d9k4871.aspx" rel="msdn"&gt;StringComparison&lt;/a&gt;-Enumeration vorhanden ist.     &lt;br /&gt;In der Praxis haben sich Trigramme, also Teilzeichenfolgen aus 3 Buchstaben, bewährt.&lt;/p&gt;  &lt;p&gt;Sehen wir uns jetzt einmal so eine Berechnung des Dice-Koeffizienten anhand des Vergleichs der Wörter &lt;em&gt;Schraubenzieher&lt;/em&gt; und &lt;em&gt;Schraubendreher&lt;/em&gt; an.     &lt;br /&gt;Nach der Zerlegung der beiden Wörter in Trigramme, ergibt sich folgendes Bild:&lt;/p&gt;  &lt;p&gt;Trigramme :&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 1,&amp;#160;&amp;#160;&amp;#160;&amp;#160; 2,&amp;#160;&amp;#160;&amp;#160; 3,&amp;#160;&amp;#160; 4,&amp;#160;&amp;#160;&amp;#160; 5,&amp;#160;&amp;#160;&amp;#160;&amp;#160; 6,&amp;#160;&amp;#160;&amp;#160; 7,&amp;#160;&amp;#160;&amp;#160;&amp;#160; 8,&amp;#160;&amp;#160;&amp;#160; 9,&amp;#160; 10,&amp;#160; 11,&amp;#160; 12,&amp;#160;&amp;#160; 13&lt;em&gt;      &lt;br /&gt;Schraubenzieher &lt;/em&gt;:&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Sch, chr, hra, rau, aub, ube, ben, enz, nzi, zie, ieh, ehe, her     &lt;br /&gt;&lt;em&gt;Schraubendreher &lt;/em&gt;:&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Sch, chr, hra, rau, aub, ube, ben, end, ndr, dre, reh, ehe, her     &lt;br /&gt;Übereinstimmungen :&amp;#160;&amp;#160;&amp;#160; 1,&amp;#160;&amp;#160;&amp;#160; 1,&amp;#160;&amp;#160;&amp;#160; 1,&amp;#160;&amp;#160;&amp;#160; 1,&amp;#160;&amp;#160;&amp;#160; 1,&amp;#160;&amp;#160;&amp;#160; 1,&amp;#160;&amp;#160;&amp;#160;&amp;#160; 1,&amp;#160;&amp;#160;&amp;#160;&amp;#160; 0,&amp;#160;&amp;#160; 0,&amp;#160;&amp;#160;&amp;#160; 0,&amp;#160;&amp;#160;&amp;#160; 0,&amp;#160;&amp;#160;&amp;#160; 1,&amp;#160;&amp;#160;&amp;#160; 1&lt;/p&gt;  &lt;p&gt;Daraus ergibt sich als Ergebnis:&lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 2*9&amp;#160; &lt;br /&gt;d(a,b )= --------- = 0,6923077 oder eine 69%ige Ähnlichkeit.     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 13+13&lt;/p&gt;  &lt;p&gt;Da die Anzahl der Übereinstimmungen immer in Relation zur Anzahl der vorhandenen Trigramme steht, ergeben sich bei sehr kurzen Wörtern immer extrem ungünstige Ähnlichkeiten. Beim Vergleich von &lt;em&gt;Maus&lt;/em&gt; und &lt;em&gt;Haus&lt;/em&gt; etwa, würde das oben beschriebene Vorgehen so aussehen,&lt;/p&gt;  &lt;p&gt;Trigramme ;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 1,&amp;#160;&amp;#160;&amp;#160; 2    &lt;br /&gt;&lt;em&gt;Maus&lt;/em&gt; ;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Mau, aus     &lt;br /&gt;&lt;em&gt;Haus&lt;/em&gt;;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Hau, aus     &lt;br /&gt;Übereinstimmungen :&amp;#160;&amp;#160; 0,&amp;#160;&amp;#160;&amp;#160;&amp;#160; 1&lt;/p&gt;  &lt;p&gt;Und als Ergebnis;&lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 2*1    &lt;br /&gt;d(a,b) = ------ = 0,25 oder eine 25%ige Ähnlichkeit.     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 2+2&lt;/p&gt;  &lt;p&gt;Um dieses Verhalten zu kompensieren, nutzt man Füllzeichen um alle Buchstaben zum Vergleich heranzuziehen. diese Füllzeichen werden am Anfang und am Ende der Zeichenkette hinzugefügt. Im folgenden Beispiel verwende ich einen “_” als Füllzeichen.&lt;/p&gt;  &lt;p&gt;Trigramme ;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 1,&amp;#160;&amp;#160;&amp;#160;&amp;#160; 2,&amp;#160;&amp;#160;&amp;#160;&amp;#160; 3,&amp;#160;&amp;#160;&amp;#160; 4,&amp;#160;&amp;#160;&amp;#160; 5,&amp;#160;&amp;#160;&amp;#160;&amp;#160; 6    &lt;br /&gt;&lt;em&gt;Maus&lt;/em&gt; ;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; __M, _Ma. Mau, aus, us_, s__     &lt;br /&gt;&lt;em&gt;Haus&lt;/em&gt;;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; __H,&amp;#160; _Ha, Hau, aus, us_,&amp;#160; s__     &lt;br /&gt;Übereinstimmungen :&amp;#160;&amp;#160;&amp;#160; 0,&amp;#160;&amp;#160;&amp;#160;&amp;#160; 0,&amp;#160;&amp;#160;&amp;#160;&amp;#160; 0,&amp;#160;&amp;#160;&amp;#160;&amp;#160; 1,&amp;#160;&amp;#160;&amp;#160; 1,&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 1&lt;/p&gt;  &lt;p&gt;Und als Ergebnis;&lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 2*3    &lt;br /&gt;d(a,b) = ------ = 0,5 oder eine 50%ige Ähnlichkeit.     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 6+6&lt;/p&gt;  &lt;p&gt;Bei der Implementierung des Algorithmus sollte dieses Verhalten bereits bei der Erzeugung der Trigramme berücksichtigt werden. Es gilt hier noch einen Schwellenwert zu bestimmen, ab welcher Wortlänge, oder Anzahl von Buchstaben, Füllzeichen verwendet werden. Für erste Versuche habe ich hier eine Größe von fünf Buchstaben bestimmt.&lt;/p&gt;  &lt;p&gt;Zur Erzeugung der Trigramme einer Zeichenfolge, habe ich als Container eine &lt;a title="List(T) Klasse" href="http://msdn.microsoft.com/library/6sh2ey19.aspx" rel="msdn"&gt;List&amp;lt;T&amp;gt;&lt;/a&gt; vom Typ &lt;a title="String Klasse" href="http://msdn.microsoft.com/s1wwdcbf.aspx" rel="msdn"&gt;string&lt;/a&gt; gewählt. Abhängig ob Füllzeichen verwendet werden, wird ein Parameter vom Typ &lt;a title="Boolean Struktur" href="http://msdn.microsoft.com/a28wyd50.aspx" rel="msdn"&gt;bool&lt;/a&gt; an die Methode übergeben.&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:f8443b94-594c-4021-9d8e-9b69e91aef5d" class="wlWriterEditableSmartContent"&gt;&lt;pre title="code" class="c#"&gt;private static List&amp;lt;string&amp;gt; GetTriGrams(string term, bool useFiller)
{
    var list = new List&amp;lt;string&amp;gt;();
    var chars = term.ToCharArray();

    if (useFiller)
    {
        list.Add("__" + chars[0]);
        list.Add("_" + chars[0] + chars[1]);
    }

    for (int i = 0; i &amp;lt; chars.Length - 2; i++)
    {
        list.Add(chars[i].ToString() + chars[i + 1] + chars[i + 2]);
    }

    if (useFiller)
    {
        list.Add(chars[chars.Length - 2].ToString() + chars[chars.Length - 1] + "_");
        list.Add(chars[chars.Length - 1].ToString() + "__");
    }

    return list;
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Jetzt muss nur noch der Inhalt der beiden Listen auf Übereinstimmungen geprüft werden. 
  &lt;br /&gt;Um Fehler bei unterschiedlich langen Listen vorzubeugen, wird als Obergrenze einer &lt;a title="for (C#-Referenz)" href="http://msdn.microsoft.com/ch45axte.aspx" rel="msdn"&gt;for&lt;/a&gt;-Schleife die Länge der kürzeren Liste verwendet. Im folgenden Listing wird für den Vergleich der Trigramme auf eine Unterscheidung der Groß- und Kleinschreibung verzichtet. Hier währe eine Überladung der Methode denkbar, der ein weitere Parameter mitgegeben wird, welcher das Verhalten beeinflusst.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:0cce55b9-f30c-4416-b2ce-6a64f167caab" class="wlWriterEditableSmartContent"&gt;&lt;pre title="code" class="c#"&gt;private static float GetSimilarity(string first, string second)
{
    bool useFiller = first.Length &amp;lt; 5 ? second.Length &amp;lt; 5 : false;
    var firstList = TriGram.GetTriGrams(first, useFiller);
    var secondList = TriGram.GetTriGrams(second, useFiller);
    var length = Math.Min(firstList.Count, secondList.Count);
    int equals = 0;

    for (int i = 0; i &amp;lt; length; i++)
    {
        if (firstList[i].Equals(
			secondList[i],
			StringComparison.OrdinalIgnoreCase))
        {
            equals++;
        }
    }

    return 2 * (float)equals /
			(float)(firstList.Count + secondList.Count);
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Eine öffentliche Methode zum ermitteln des Dice-Koeffizienten zweier Wörter könnte in etwa so aussehen:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:ae7d0382-3963-473b-9fd9-b110be8546ba" class="wlWriterEditableSmartContent"&gt;&lt;pre title="code" class="c#"&gt;public static float Similarity(string first, string second)
{
    if (string.IsNullOrEmpty(first))
    {
        throw new ArgumentException(
			"first ist ein null-Verweis oder eine leere Zeichenfolge.",
			"first");
    }

    if (string.IsNullOrEmpty(second))
    {
        throw new ArgumentException(
			"second ist ein null-Verweis oder eine leere Zeichenfolge.",
			"second");
    }

    return TriGram.GetSimilarity(first, second);
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Oder die Ermittlung der Ähnlichkeit unter Angabe eines Schwellenwertes in etwa so:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:87066252-59e2-4da5-b045-bcb076e73f0e" class="wlWriterEditableSmartContent"&gt;&lt;pre title="code" class="c#"&gt;public static bool IsSimilar(string first, string second, float threshold)
{
    if (string.IsNullOrEmpty(first))
    {
        throw new ArgumentException(
			"first ist ein null-Verweis oder eine leere Zeichenfolge.",
			"first");
    }

    if (string.IsNullOrEmpty(second))
    {
        throw new ArgumentException(
			"second ist ein null-Verweis oder eine leere Zeichenfolge.",
			"second");
    }

    return TriGram.GetSimilarity(first, second) &amp;gt;= threshold;
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Wie man anhand der Beispiele sehen kann, sind hier viele Möglichkeiten gegeben. 
  &lt;br /&gt;Es währe durchaus auch eine Methode vorstellbar, welche die beste Übereinstimmung aus einer Liste von Wörtern wählt. 

  &lt;br /&gt;Eine Verwendungsmöglichkeit sehe ich überall dort, wo nicht die Übereinstimmung von Zeichenfolgen gefragt ist, sondern die Ähnlichkeit.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:f5053271-0db7-464f-a3d2-26122ce86fea" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/c%23" rel="tag"&gt;c#&lt;/a&gt;,&lt;a href="http://technorati.com/tags/algorithm" rel="tag"&gt;algorithm&lt;/a&gt;,&lt;a href="http://technorati.com/tags/dice+coefficient" rel="tag"&gt;dice coefficient&lt;/a&gt;,&lt;a href="http://technorati.com/tags/linguistics" rel="tag"&gt;linguistics&lt;/a&gt;,&lt;a href="http://technorati.com/tags/searching" rel="tag"&gt;searching&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/E3Myj40x8bxv5e87pJ7_LPjdnXo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/E3Myj40x8bxv5e87pJ7_LPjdnXo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/E3Myj40x8bxv5e87pJ7_LPjdnXo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/E3Myj40x8bxv5e87pJ7_LPjdnXo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=ZwX1kKYuX-U:UdPdAYYjqUE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=ZwX1kKYuX-U:UdPdAYYjqUE:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=ZwX1kKYuX-U:UdPdAYYjqUE:1DmhQM8_AdY"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=1DmhQM8_AdY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/klaus_b/~4/ZwX1kKYuX-U" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/ZwX1kKYuX-U/post.aspx</link>
      <author>klaus_b0@hotmail.de (klaus_b)</author>
      <comments>http://blog.klaus-b.net/post/2009/10/25/Vergleichen-von-Wortern-mit-dem-Dice-Koeffizienten.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=9c320c42-bda3-4ac0-813d-48761f885e62</guid>
      <pubDate>Sun, 25 Oct 2009 17:01:04 +0100</pubDate>
      <category>C#</category>
      <dc:publisher>klaus_b0@hotmail.de (klaus_b)</dc:publisher>
      <pingback:server>http://blog.klaus-b.net/pingback.axd</pingback:server>
      <pingback:target>http://blog.klaus-b.net/post.aspx?id=9c320c42-bda3-4ac0-813d-48761f885e62</pingback:target>
      <slash:comments>1</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=9c320c42-bda3-4ac0-813d-48761f885e62</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2009/10/25/Vergleichen-von-Wortern-mit-dem-Dice-Koeffizienten.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=9c320c42-bda3-4ac0-813d-48761f885e62</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=9c320c42-bda3-4ac0-813d-48761f885e62</feedburner:origLink></item>
    <item>
      <title>Eine Enumeration in einer XML-Konfiguration verwenden</title>
      <description>&lt;p&gt;… ist einfacher als ich dachte.    &lt;br /&gt;In einem aktuellen Projekt sollte die zu verwendende Culture als Attribut in der web.config angegeben werden. Da im Moment nur die Culture-Werte “en” und “de” verarbeitet werden können, soll der Benutzer auch nur diese zur Auswahl erhalten. Also musste irgendwo eine Enumeration definiert werden, welche vom Attribut Culture verwendet wird.     &lt;br /&gt;Da die Verarbeitung von eigenen &lt;a title="ConfigurationSection Klasse" href="http://msdn.microsoft.com/x0kca287.aspx" rel="msdn"&gt;ConfigurationSection&lt;/a&gt; im allgemeinen sehr codeintensiv ist, stellte ich mir die Umsetzung auch dementsprechend kompliziert vor.&lt;/p&gt;  &lt;p&gt;Weit gefehlt.    &lt;br /&gt;Die Angewohnheit, zu einem benutzerdefinierten Konfigurationsabschnitt auch immer eine Schemadatei zu erstellen, kam mir in diesem Fall sehr zu Gute.     &lt;br /&gt;Beim durchforsten der Dokumentation zu &lt;a title="XML Schema" href="http://de.wikipedia.org/wiki/XML_Schema" rel="wiki"&gt;XML Schema&lt;/a&gt; bin ich wieder einmal auf das &lt;a title="simpleType Element" href="http://msdn.microsoft.com/ms256050.aspx" rel="msdn"&gt;simpleType&lt;/a&gt;-Element gestoßen, dem ich bis jetzt keine große Bedeutung beigemessen hatte.     &lt;br /&gt;Ein Fehler, wie sich gleich zeigen wird.     &lt;br /&gt;    &lt;br /&gt;Das simpleType-Element bietet das Attribut &lt;strong&gt;xs:restriction&lt;/strong&gt; und dieses wiederum &lt;strong&gt;xs:enumeration&lt;/strong&gt;. Tja, so Einfach kann es sein.     &lt;br /&gt;Ich brauchte nur die Zeile&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:f7250e9b-62a7-4854-a960-e70728c3558b" class="wlWriterEditableSmartContent"&gt;&lt;pre title="code" class="xml:nogutter"&gt;&amp;lt;xs:attribute name="culture" use="optional" type="xs:string" /&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;durch folgende Zeilen zu ersetzen.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:afad3269-fd2e-43c4-9ae4-6eeb084b8fb4" class="wlWriterEditableSmartContent"&gt;&lt;pre title="code" class="xml:nogutter"&gt;&amp;lt;xs:attribute name="culture" use="optional"&amp;gt;
  &amp;lt;xs:simpleType&amp;gt;
    &amp;lt;xs:restriction base="xs:string"&amp;gt;
      &amp;lt;xs:enumeration value="de" /&amp;gt;
      &amp;lt;xs:enumeration value="en" /&amp;gt;
    &amp;lt;/xs:restriction&amp;gt;
  &amp;lt;/xs:simpleType&amp;gt;
&amp;lt;/xs:attribute&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Schon hatte ich die gewünschte Auswahl-Enumeration in der web.config zur Verfügung.&lt;/p&gt;

&lt;p&gt;&lt;img style="display: inline" title="XmlEnumeration_001" alt="XmlEnumeration_001" src="http://blog.klaus-b.net/image.axd?picture=XmlEnumeration_001.png" width="549" height="291" /&gt; &lt;/p&gt;

&lt;p&gt;Sollten weitere Culture-Einstellungen hinzukommen, sind diese sehr einfach im XML Schema nachzupflegen.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:2110ef99-8249-4cb9-b78b-e44966341a0c" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/XML" rel="tag"&gt;XML&lt;/a&gt;,&lt;a href="http://technorati.com/tags/config" rel="tag"&gt;config&lt;/a&gt;,&lt;a href="http://technorati.com/tags/XML-Schema" rel="tag"&gt;XML-Schema&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Enumeration" rel="tag"&gt;Enumeration&lt;/a&gt;&lt;/div&gt;

&lt;div style="margin-top: 10px; height: 15px" class="zemanta-pixie"&gt;&lt;img style="border-bottom-style: none; border-right-style: none; border-top-style: none; float: right; border-left-style: none" class="zemanta-pixie-img" alt="" src="http://img.zemanta.com/pixy.gif?x-id=9fc67582-10e0-419e-ab93-9ef1acd1cb54" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/IApbC7JzwWQyefcsu80Tv92NVbo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/IApbC7JzwWQyefcsu80Tv92NVbo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/IApbC7JzwWQyefcsu80Tv92NVbo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/IApbC7JzwWQyefcsu80Tv92NVbo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=xwQPiZfivts:6DvbQpohQb4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=xwQPiZfivts:6DvbQpohQb4:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=xwQPiZfivts:6DvbQpohQb4:1DmhQM8_AdY"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=1DmhQM8_AdY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/klaus_b/~4/xwQPiZfivts" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/xwQPiZfivts/post.aspx</link>
      <author>klaus_b0@hotmail.de (klaus_b)</author>
      <comments>http://blog.klaus-b.net/post/2009/10/17/Eine-Enumeration-in-einer-XML-Konfiguration-verwenden.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=70481e63-81cd-45d8-98ff-1fd692fc8735</guid>
      <pubDate>Sat, 17 Oct 2009 18:09:24 +0100</pubDate>
      <category>ASP.NET</category>
      <dc:publisher>klaus_b0@hotmail.de (klaus_b)</dc:publisher>
      <pingback:server>http://blog.klaus-b.net/pingback.axd</pingback:server>
      <pingback:target>http://blog.klaus-b.net/post.aspx?id=70481e63-81cd-45d8-98ff-1fd692fc8735</pingback:target>
      <slash:comments>1</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=70481e63-81cd-45d8-98ff-1fd692fc8735</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2009/10/17/Eine-Enumeration-in-einer-XML-Konfiguration-verwenden.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=70481e63-81cd-45d8-98ff-1fd692fc8735</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=70481e63-81cd-45d8-98ff-1fd692fc8735</feedburner:origLink></item>
    <item>
      <title>Eine Anwendung soll nur einmal geöffnet werden können</title>
      <description>&lt;p&gt;…war eine &lt;a title="WPF-Anwendung darf nur einmal zugleich offen sein" href="http://codekicker.de/fragen/WPF-Anwendung-darf-nur-einmal-zugleich-offen-sein/108"&gt;Frage auf codekicker.de&lt;/a&gt;. Aus der Frage entwickelte sich eine interessante Diskussion rund um die verschiedenen Möglichkeiten dies zu Bewerkstelligen.     &lt;br /&gt;Einer der ersten Vorschläge war die Verwendung eines &lt;a title="Mutex Klasse" href="http://msdn.microsoft.com/01985e8f.aspx" rel="msdn"&gt;Mutex&lt;/a&gt;, gefolgt von der Verwendung einer Datei deren Anwesenheit die Ausführung der Anwendung signalisiert.&lt;/p&gt;  &lt;p&gt;Mein persönlicher Favorit ist nach wie vor die Verwendung der systemeigenen Prozessliste, in der jeder ausgeführte Prozess vom System erfasst und aufgeführt wird. &lt;a title="GENiALi&amp;#39;s Blog - Inklusive Rechtschreibfehler" href="http://blog.geniali.ch/"&gt;GENiALi&lt;/a&gt; brachte daraufhin den Einwand:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;“ &lt;em&gt;Nach dem Prozess suchen? Wenn der User mal ein Progi umtauft, von app.exe auf Application.exe? Dann wird nichts mehr daraus.&lt;/em&gt; “&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Damit hat er prinzipiell Recht, wenn man den Namen der Anwendung “hart verdrahtet”. Ich habe nie erwähnt, den Namen der Anwendung irgendwo zu hinterlegen.&lt;/p&gt;  &lt;p&gt;Genau dafür bietet die &lt;a title="Process Klasse" href="http://msdn.microsoft.com/ccf1tfx0.aspx" rel="msdn"&gt;Process&lt;/a&gt;-Klasse die statische Methode &lt;a title="Process.GetCurrentProcess Methode" href="http://msdn.microsoft.com/s6aca5ys.aspx" rel="msdn"&gt;GetCurrentProcess&lt;/a&gt; an. mit dieser Methode wird der aktuelle Prozess der aufrufenden Methode in eine Instanz der Process-Klasse zurückgegeben. In dieser Process-Instanz ist jetzt alles nötige enthalten. Die ID des Prozess genauso wie der Name. Über das Hauptmodul des Prozess, zu erhalten über die Eigenschaft &lt;a title="Process.MainModule Eigenschaft" href="http://msdn.microsoft.com/6khbeh3e.aspx" rel="msdn"&gt;MainModule&lt;/a&gt; der Process-Instanz, kann auch der komplette Pfad zu Vergleichen herangezogen werden. Verpackt in ein paar Zeilen Code, lässt sich damit eine sehr effektive Methode erstellen, die sehr zuverlässig die Einmaligkeit der Ausführung einer Anwendung gewährleistet.&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:18a0214f-e3ba-449d-8b6a-fa39604b65ec" class="wlWriterEditableSmartContent"&gt;&lt;pre title="code" class="c#:firstline[30]"&gt;/// &amp;lt;summary&amp;gt;
/// Prüft ob die Anwendung bereits ausgeführt wird.
/// &amp;lt;/summary&amp;gt;
/// &amp;lt;returns&amp;gt;
/// &amp;lt;c&amp;gt;true&amp;lt;/c&amp;gt; wenn die Anwendung bereits läuft,
/// anderenfalls &amp;lt;c&amp;gt;false&amp;lt;/c&amp;gt;.
/// &amp;lt;/returns&amp;gt;
/// &amp;lt;remarks&amp;gt;n/a&amp;lt;/remarks&amp;gt;
private static bool AlreadyRunning()
{
    Process current = Process.GetCurrentProcess();
    Process[] processes = Process.GetProcessesByName(
							current.ProcessName);

    foreach (Process process in processes)
    {
        if (process.Id != current.Id)
        {
            if (Assembly.GetExecutingAssembly().Location
				.Replace("/", "\\") == current.MainModule.FileName)
            {

                return true;
            }
        }
    }

    return false;
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Somit lässt sich in einem einzigen Statement prüfen ob die Anwendung bereits läuft oder nicht.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:ea39907e-daaa-489d-998b-2936ec414597" class="wlWriterEditableSmartContent"&gt;&lt;pre title="code" class="c#:firstline[12]"&gt;/// &amp;lt;summary&amp;gt;
/// Der Haupteinstiegspunkt für die Anwendung.
/// &amp;lt;/summary&amp;gt;
[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    if (Program.AlreadyRunning())
    {
        Application.Exit();
        return;
    }

    Application.Run(new Form1());
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Dabei sollte es keine Rolle spielen ob die Anwendung eine Konsolenanwendung, eine Windows Forms Anwendung oder eine WPF Anwendung ist.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:d0916bce-c71e-4da9-a7bf-1ac98a8ece04" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/c%23" rel="tag"&gt;c#&lt;/a&gt;,&lt;a href="http://technorati.com/tags/windows+forms" rel="tag"&gt;windows forms&lt;/a&gt;,&lt;a href="http://technorati.com/tags/single+instance" rel="tag"&gt;single instance&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/yc-zVmdALsqekTK3ZqSKO9T7BMc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/yc-zVmdALsqekTK3ZqSKO9T7BMc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/yc-zVmdALsqekTK3ZqSKO9T7BMc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/yc-zVmdALsqekTK3ZqSKO9T7BMc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=vnPKLFzdr_k:lWmbMiZhGkE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=vnPKLFzdr_k:lWmbMiZhGkE:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=vnPKLFzdr_k:lWmbMiZhGkE:1DmhQM8_AdY"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=1DmhQM8_AdY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/klaus_b/~4/vnPKLFzdr_k" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/vnPKLFzdr_k/post.aspx</link>
      <author>klaus_b0@hotmail.de (klaus_b)</author>
      <comments>http://blog.klaus-b.net/post/2009/08/28/Eine-Anwendung-soll-nur-einmal-geoffnet-werden-konnen.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=7d79deee-a1e5-4b92-a6dc-b89495261fef</guid>
      <pubDate>Fri, 28 Aug 2009 16:41:28 +0100</pubDate>
      <category>C#</category>
      <dc:publisher>klaus_b0@hotmail.de (klaus_b)</dc:publisher>
      <pingback:server>http://blog.klaus-b.net/pingback.axd</pingback:server>
      <pingback:target>http://blog.klaus-b.net/post.aspx?id=7d79deee-a1e5-4b92-a6dc-b89495261fef</pingback:target>
      <slash:comments>9</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=7d79deee-a1e5-4b92-a6dc-b89495261fef</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2009/08/28/Eine-Anwendung-soll-nur-einmal-geoffnet-werden-konnen.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=7d79deee-a1e5-4b92-a6dc-b89495261fef</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=7d79deee-a1e5-4b92-a6dc-b89495261fef</feedburner:origLink></item>
    <item>
      <title>codekicker, eine neue Seite in der Community</title>
      <description>&lt;p&gt;&lt;img style="display: inline; margin-left: 0px; margin-right: 0px" title="codekicker.de" alt="codekicker.de" align="left" src="http://blog.klaus-b.net/image.axd?picture=codekicker_logo.png" width="120" height="24" /&gt; Mehr oder weniger durch Zufall bin ich über &lt;a title="Fragen und Antworten zum Thema Programmieren" href="http://codekicker.de/"&gt;codekicker&lt;/a&gt; gestolpert; und war sehr schnell vom Konzept der Seite begeistert.     &lt;br /&gt;Codekicker ist keines der üblichen Foren wie man sie kennt. Die Verantwortlichen Felix Schad und Marvin Steppat, beides Studenten der &lt;a class="zem_slink" title="University of Karlsruhe (TH)" href="http://www.uni-karlsruhe.de/" rel="homepage"&gt;Uni Karlsruhe&lt;/a&gt;, haben sich ein nettes Konzept einfallen lassen. Hier ein Auszug aus der &lt;a title="codekicker.de - FAQ" href="http://codekicker.de/faq"&gt;FAQ&lt;/a&gt; der Seite.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;codekicker ist eine Webseite für Fragen und Antworten rund um das Thema Programmieren. Benutzer können Fragen stellen und Fragen beantworten, genau wie in einem &lt;b&gt;Forum&lt;/b&gt;. &lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;codekicker ist aber auch eine &lt;b&gt;Wiki&lt;/b&gt; - Fragen und Antworten können von der Community editiert werden, um sie zu verbessern und Fehler zu beseitigen. So steigen Fragen mit der Zeit in ihrer Qualität und verlieren nie an Aktualität. &lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#3a3a3a"&gt;&lt;font color="#000000"&gt;&lt;em&gt;codekicker wird nicht von uns betrieben - wir machen nur die Technik. codekicker ist die Community aus Programmierern, die von Anderen lernen und ihr Wissen teilen möchten. Daher werden Fragen und Antworten auch nicht von uns moderiert oder zensiert. Dafür ist die Community selbst verantwortlich&lt;/em&gt;&lt;/font&gt;.&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Es gibt keine von den Betreibern ernannten Administratoren oder Moderatoren. Die Aufgaben erledigen die Mitglieder der Seite selbst. Allerdings muss jeder einzelne sich das Recht für entsprechende Privilegien durch das Vertrauen der Mitglieder verdienen.&lt;/p&gt;  &lt;p&gt;Das Kernstück des Bewertungssystems bildet die Reputation. Wird eine Frage oder Antwort für gut befunden, kann man eine positive Bewertung abgeben. Der Verfasser der Frage oder Antwort erhält dann 10 Reputationspunkte. Empfindet man eine Antwort als unzureichend oder falsch, kann man diese auch negativ bewerten. Dem Verfasser werden dann 10 Punkte von seiner Reputation abgezogen.    &lt;br /&gt;Je mehr Punkte man auf seinem Konto verbuchen kann, desto höher ist natürlich die Reputation und dementsprechend auch die Rechte auf der Seite.     &lt;br /&gt;So kann ein Benutzer der über 100 Reputationspunkte verfügt auch negativ bewerten. Um eine Antwort eines anderen Mitglied editieren zu können, bedarf es bereits 500 Reputationspunkte.&lt;/p&gt;  &lt;p&gt;Neben der Reputation werden noch sogenannte Abzeichen in den Stufen Bronze, Silber und Gold vergeben. Dies werden einzelnen Mitgliedern für entsprechende Aktivität verliehen.    &lt;br /&gt;Silber und Gold erhält man z.B. für Fragen und Antworten die sehr oft positiv bewertet wurden.&lt;/p&gt;  &lt;p&gt;Es werden noch viele weitere und sehr interessante Feature geboten wie etwa ein Kopfgeld aussetzen, Fragen und Antworten direkt kommentieren, die Aktivitäten der einzelnen Mitglieder direkt in ihrem Profil sehen udgl.&lt;/p&gt;  &lt;p&gt;Im großen und ganzen empfinde ich die Seite als echte Bereicherung der deutschsprachigen Entwicklergemeinde.&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:9e1f1fb2-8661-4e94-b23e-3d921e662cb2" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/community" rel="tag"&gt;community&lt;/a&gt;,&lt;a href="http://technorati.com/tags/developer" rel="tag"&gt;developer&lt;/a&gt;,&lt;a href="http://technorati.com/tags/german+community" rel="tag"&gt;german community&lt;/a&gt;&lt;/div&gt;  &lt;div style="margin-top: 10px; height: 15px" class="zemanta-pixie"&gt;&lt;img style="border-bottom-style: none; border-right-style: none; border-top-style: none; float: right; border-left-style: none" class="zemanta-pixie-img" alt="" src="http://img.zemanta.com/pixy.gif?x-id=783346a3-1213-492b-9f73-d8c8a11ca5fb" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/xQA4e_q3YDuFyYevlSMBfAp1enw/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/xQA4e_q3YDuFyYevlSMBfAp1enw/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/xQA4e_q3YDuFyYevlSMBfAp1enw/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/xQA4e_q3YDuFyYevlSMBfAp1enw/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=W0fU8xdPtoc:TaWpg3XGazg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=W0fU8xdPtoc:TaWpg3XGazg:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=W0fU8xdPtoc:TaWpg3XGazg:1DmhQM8_AdY"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=1DmhQM8_AdY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/klaus_b/~4/W0fU8xdPtoc" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/W0fU8xdPtoc/post.aspx</link>
      <author>klaus_b0@hotmail.de (klaus_b)</author>
      <comments>http://blog.klaus-b.net/post/2009/08/22/codekicker-eine-neue-Seite-in-der-Community.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=96e872d0-b76a-4823-ae9a-f400da0ae6fe</guid>
      <pubDate>Sat, 22 Aug 2009 13:07:03 +0100</pubDate>
      <category>Community</category>
      <dc:publisher>klaus_b0@hotmail.de (klaus_b)</dc:publisher>
      <pingback:server>http://blog.klaus-b.net/pingback.axd</pingback:server>
      <pingback:target>http://blog.klaus-b.net/post.aspx?id=96e872d0-b76a-4823-ae9a-f400da0ae6fe</pingback:target>
      <slash:comments>2</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=96e872d0-b76a-4823-ae9a-f400da0ae6fe</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2009/08/22/codekicker-eine-neue-Seite-in-der-Community.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=96e872d0-b76a-4823-ae9a-f400da0ae6fe</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=96e872d0-b76a-4823-ae9a-f400da0ae6fe</feedburner:origLink></item>
    <item>
      <title>Die Suche von Blogengine.NET und Sonderzeichen</title>
      <description>&lt;p&gt;Wer sein Blog mit &lt;a title="BlogEngine.NET" href="http://www.dotnetblogengine.net/"&gt;Blogengine.NET&lt;/a&gt; betreibt und auch einmal die Suche mit Ausdrücken gefüttert hat die Sonderzeichen enthalten, wird beim Blättern durch die Ergebnisse bestimmt auch auf folgende Unart gestoßen sein: Beim neubilden der &lt;a title="Uniform Resource Locator" href="http://de.wikipedia.org/wiki/Uniform_Resource_Locator" rel="wiki"&gt;URL&lt;/a&gt; schneidet Blogengine.NET die Zeichenfolge ab dem Sonderzeichen einfach ab. Nehmen wir als Beispiel einmal den Ausdruck &lt;strong&gt;C#&lt;/strong&gt;. Bei der Eingabe in die Suchmaske und der Ausgabe auf der Ergebnisseite geht noch alles glatt. Sobald aber auf den Link einer weitere Ergebnisseite geklickt wird, erscheint nur noch der Buchstabe &lt;strong&gt;C&lt;/strong&gt; als Ausdruck zur Abfrage. Das Rautenzeichen &lt;strong&gt;#&lt;/strong&gt; und alles was darauf folgt wird einfach entfernt.&lt;/p&gt;  &lt;p&gt;Woher kommt dieses Verhalten? Die Lösung ist mehr als simpel: an der falschen Kodierung der Abfragezeichenfolge aus dem &lt;a title="HttpRequest.QueryString Eigenschaft" href="http://msdn.microsoft.com/ktw1eyx1.aspx" rel="msdn"&gt;QueryString&lt;/a&gt;.     &lt;br /&gt;Blogengine.NET kodiert den QueryString mit der Methode &lt;a title="HttpServerUtility&amp;#10;.HtmlEncode Methode" href="http://msdn.microsoft.com/8dyzz8s9.aspx" rel="msdn"&gt;HtmlEncode&lt;/a&gt; zum zurücksenden an den Server. Besser geeignet ist hier die Methode &lt;a title="HttpServerUtility&amp;#10;.UrlEncode Methode" href="http://msdn.microsoft.com/axc6fkkb.aspx" rel="msdn"&gt;UrlEncode&lt;/a&gt;. Wie der Name schon sagt, kodiert diese Methode eine Zeichenfolge zur Verwendung in einer URL.&lt;/p&gt;  &lt;p&gt;Mit folgender kleinen Anpassung in der privaten Methode &lt;em&gt;BindPaging&lt;/em&gt; der Klasse &lt;em&gt;search, &lt;/em&gt;zu finden im Wurzelverzeichnis der Anwendung, lässt sich dieses unschöne Verhalten beheben:&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:0645486f-706a-4e5f-8913-5e4571b5ca46" class="wlWriterEditableSmartContent"&gt;&lt;pre title="code" class="c#:firstline[198]"&gt;//a.HRef = "?q=" + Server.HtmlEncode(Request.QueryString["q"]) + comment + "&amp;amp;amp;page=" + (i + 1);
a.HRef = "?q=" + Server.UrlEncode(Request.QueryString["q"]) + comment + "&amp;amp;amp;page=" + (i + 1);&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Leider habe ich keine andere Möglichkeit gefunden das Verhalten der Suche zu ändern, als die direkte Änderung im Quelltext.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:199857a4-b6a2-4d4e-a176-8148d3bd56bf" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/blogengine.net" rel="tag"&gt;blogengine.net&lt;/a&gt;,&lt;a href="http://technorati.com/tags/searching" rel="tag"&gt;searching&lt;/a&gt;,&lt;a href="http://technorati.com/tags/special+characters" rel="tag"&gt;special characters&lt;/a&gt;&lt;/div&gt;

&lt;div style="margin-top: 10px; height: 15px" class="zemanta-pixie"&gt;&lt;img style="border-bottom-style: none; border-right-style: none; border-top-style: none; float: right; border-left-style: none" class="zemanta-pixie-img" alt="" src="http://img.zemanta.com/pixy.gif?x-id=da28a5b1-ee3d-4f07-87d1-097f30a73d77" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/fPQPPKUjPNrMpsywsMnGyLmTb_I/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/fPQPPKUjPNrMpsywsMnGyLmTb_I/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/fPQPPKUjPNrMpsywsMnGyLmTb_I/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/fPQPPKUjPNrMpsywsMnGyLmTb_I/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=W5hmnSQ6jiU:kCsxRvtnaN8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=W5hmnSQ6jiU:kCsxRvtnaN8:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=W5hmnSQ6jiU:kCsxRvtnaN8:1DmhQM8_AdY"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=1DmhQM8_AdY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/klaus_b/~4/W5hmnSQ6jiU" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/W5hmnSQ6jiU/post.aspx</link>
      <author>klaus_b0@hotmail.de (klaus_b)</author>
      <comments>http://blog.klaus-b.net/post/2009/08/15/Die-Suche-von-BlogengineNET-und-Sonderzeichen.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=bc5a1597-a097-47ac-92ac-4df48a0f0aaa</guid>
      <pubDate>Sat, 15 Aug 2009 13:44:35 +0100</pubDate>
      <category>Blogengine.NET</category>
      <dc:publisher>klaus_b0@hotmail.de (klaus_b)</dc:publisher>
      <pingback:server>http://blog.klaus-b.net/pingback.axd</pingback:server>
      <pingback:target>http://blog.klaus-b.net/post.aspx?id=bc5a1597-a097-47ac-92ac-4df48a0f0aaa</pingback:target>
      <slash:comments>7</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=bc5a1597-a097-47ac-92ac-4df48a0f0aaa</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2009/08/15/Die-Suche-von-BlogengineNET-und-Sonderzeichen.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=bc5a1597-a097-47ac-92ac-4df48a0f0aaa</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=bc5a1597-a097-47ac-92ac-4df48a0f0aaa</feedburner:origLink></item>
    <item>
      <title>Ein Thesaurus-Modell zur Verwendung in einer Suche</title>
      <description>&lt;div style="margin: 1em; width: 310px; display: block; float: right" class="zemanta-img" jquery1250155657581="5289"&gt;&lt;a href="http://commons.wikipedia.org/wiki/Image:Sacrecon.png"&gt;&lt;img style="border-bottom: medium none; border-left: medium none; display: block; border-top: medium none; border-right: medium none" alt="The first paragraph of Dictionarium sive thesa..." src="http://upload.wikimedia.org/wikipedia/commons/thumb/3/38/Sacrecon.png/300px-Sacrecon.png" width="310" height="200" /&gt;&lt;/a&gt;     &lt;p style="font-size: 0.8em" class="zemanta-img-attribution"&gt;Image via &lt;a href="http://commons.wikipedia.org/wiki/Image:Sacrecon.png"&gt;Wikipedia&lt;/a&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;&lt;a title="Thesaurus" href="http://de.wikipedia.org/wiki/Thesaurus" rel="wiki"&gt;Thesauri&lt;/a&gt; finden ihre Verwendung in den verschiedensten Einsatzgebieten. Vom einfachen Wörterbuch über die Unterstützung einer Volltextsuche bis hin zu polyhierarchischen Relationen in komplexen Dokumentationen.     &lt;br /&gt;Ich bin allerdings nur an einer Lösung zur Implementierung von Thesaurus-Feature in einer Volltextsuche interessiert. Bei der Verwendung eines Thesaurus in einer Suche wird er meist für zwei Aufgaben verwendet: der Erweiterung und Ersetzung von Suchbegriffen.&lt;/p&gt;  &lt;p&gt;Die Erweiterung von Suchbegriffen erscheint mir wesentlich Sinnvoller als das ersetzen von einzelnen Suchwörtern. Vielleicht sehe ich das nur etwas zu eng, aber für mein Empfinden hat das Ersetzen von Suchwörtern etwas von Zensur.&lt;/p&gt;  &lt;p&gt;Beim erweitern von Suchbegriffen geht es im wesentlichen um die Verwendung von Synonymen zu einem bestimmten Wort. Gibt ein Benutzer einer Webseite z.B.: &lt;strong&gt;JS&lt;/strong&gt; ein, so soll auch automatisch nach &lt;strong&gt;&lt;a title="JScript" href="http://de.wikipedia.org/wiki/JScript" rel="wiki"&gt;JScript&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a title="JavaScript" href="http://de.wikipedia.org/wiki/JavaScript" rel="wiki"&gt;JavaScript&lt;/a&gt;&lt;/strong&gt; und &lt;strong&gt;Java Script&lt;/strong&gt; gesucht werden. Damit die jeweilige Suche diese Erweiterung auch bewerkstelligen kann, muss die Thesaurus-Funktionalität irgendwie zur Verfügung gestellt werden.&lt;/p&gt;  &lt;p&gt;Als erstes müssen die Synonyme eines bestimmten Worts irgendwo hierarchisch zusammengefasst werden. Als einfachste Lösung habe ich mich hier für folgende &lt;a title="XML" href="http://de.wikipedia.org/wiki/XML" rel="wiki"&gt;XML&lt;/a&gt;-Datei entschieden:&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:f01ba436-4b0d-44c7-99df-2931836f0196" class="wlWriterEditableSmartContent"&gt;&lt;pre title="code" class="c#:nogutter"&gt;&amp;lt;?xml version="1.0" encoding="utf-8" ?&amp;gt;
&amp;lt;thesaurus xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Thesaurus.xsd"&amp;gt;
  &amp;lt;extension&amp;gt;
    &amp;lt;syn&amp;gt;JS&amp;lt;/syn&amp;gt;
    &amp;lt;syn&amp;gt;JScript&amp;lt;/syn&amp;gt;
    &amp;lt;syn&amp;gt;JavaScript&amp;lt;/syn&amp;gt;
    &amp;lt;syn&amp;gt;Java Script&amp;lt;/syn&amp;gt;
  &amp;lt;/extension&amp;gt;
  &amp;lt;extension&amp;gt;
    &amp;lt;syn&amp;gt;MS&amp;lt;/syn&amp;gt;
    &amp;lt;syn&amp;gt;Microsoft&amp;lt;/syn&amp;gt;
  &amp;lt;/extension&amp;gt;
  &amp;lt;extension&amp;gt;
    &amp;lt;syn&amp;gt;VB&amp;lt;/syn&amp;gt;
    &amp;lt;syn&amp;gt;Visual Basic&amp;lt;/syn&amp;gt;
  &amp;lt;/extension&amp;gt;
&amp;lt;/thesaurus&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Wie im obigen Listing zu sehen, ist das Schema der XML-Datei sehr einfach aufgebaut. 
  &lt;br /&gt;Jede Erweiterung enthält für jedes mögliche Synonym einen eigenen Kind-Knoten. Falls es später einmal nötig sein sollte auch Ersetzungen zu unterstützen, kann das sehr einfach “nachgerüstet” werden. 

  &lt;br /&gt;Um die Datenstruktur in Objekten abzubilden, habe ich mir folgende Lösung überlegt:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Zur Abbildung eines Knoten &amp;lt;extension&amp;gt; verwende ich eine Klasse, die alle Synonyme in einer Aufzählung vorhält. &lt;/li&gt;

  &lt;li&gt;Synonyme müssen nur hinzugefügt werden können. &lt;/li&gt;

  &lt;li&gt;Es muss überprüfbar sein, ob ein bestimmtes Synonym bereits in der Instanz enthalten ist. &lt;/li&gt;

  &lt;li&gt;Alle Klassen mit ihren enthaltenen Synonymen werden in einer Aufzählung gesammelt die den Thesaurus darstellt. &lt;/li&gt;

  &lt;li&gt;Jedes Synonym muss im Thesaurus einzigartig sein. &lt;/li&gt;

  &lt;li&gt;Alle in der Aufzählung enthaltenen Synonyme sind über einen Index jederzeit abrufbar. &lt;/li&gt;

  &lt;li&gt;Jeder der Knoten &amp;lt;extension&amp;gt; ist über jeden seiner enthaltenen Synonyme als ganzer Knoten abrufbar. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Entstanden ist aus diesen Vorgaben folgendes Konstrukt: &lt;/p&gt;

&lt;p&gt;&lt;img style="display: inline" title="Thesaurus Diagram" alt="Thesaurus Diagram" src="http://blog.klaus-b.net/image.axd?picture=Thesaurus_CD.png" width="520" height="234" /&gt; &lt;/p&gt;

&lt;p&gt;Da die Thesaurus-Funktionalität nicht für eine Verwendung außerhalb der Suche vorgesehen ist, sind die öffentlichen Methoden auf die Abfrage eines bestimmten Synonym und die Rückgabe einer Instanz der Klasse &lt;em&gt;ThesaurusExtension&lt;/em&gt; begrenzt. 

  &lt;br /&gt;Um das laden der Thesaurus-Datei und die Abbildung des Inhalts kümmert sich komplett die Klasse Thesaurus. Sie reagiert ebenfalls auf Änderungen an der Thesaurus-Datei und erstellt das Objekt-Abbild derselben gegebenenfalls neu. 

  &lt;br /&gt;Dementsprechend Einfach ist die Verwendung dieses Thesaurus. Es braucht nur geprüft zu werden ob ein bestimmtes Suchwort, im oben genannten Beispiel &lt;strong&gt;JS&lt;/strong&gt;, im Thesaurus enthalten ist. Wird &lt;em&gt;true&lt;/em&gt; zurückgegeben, kann mit der Methode Find die entsprechende Instanz der Klasse &lt;em&gt;ThesaurusExtension&lt;/em&gt; abgefragt werden. Natürlich wird auch bei der Abfrage nach anderen Synonymen der Instanz, etwa &lt;strong&gt;JScript&lt;/strong&gt; oder &lt;strong&gt;JavaScript&lt;/strong&gt;, ebenfalls diese Instanz zurückgegeben. In der Eigenschaft &lt;em&gt;Synonyms&lt;/em&gt; der Instanz befinden sich alle dem Suchwort entsprechenden Synonyme und können den Suchwörtern hinzugefügt werden.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:6474bc9d-a8d7-440d-9ca0-b62d30159617" class="wlWriterEditableSmartContent"&gt;&lt;pre title="code" class="c#:firstline[269]"&gt;// Liste für Synonyme erzeugen
List&amp;lt;string&amp;gt; expanded = new List&amp;lt;string&amp;gt;();

// nach Synonymen suchen
foreach (var word in searchTerms)
{
	// wenn der Thesaurus das Suchwort enthält
    if (this.thesaurus.Contains(word))
    {
		// durch die Synonyme iterieren
        foreach(var entry in thesaurus.Find(word).Synonyms)
        {
			// wenn das Synonym nicht gleich
			// dem Suchwort ist
            if (!word.Equals(entry,
					StringComparison.OrdinalIgnoreCase))
            {
				// als erweiterter Suchbegriff hinzufügen
                expanded.Add(entry);
            }
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Da der Thesaurus lediglich eine Auflistung von Objekten darstellt, kann er, wie bereits weiter oben erwähnt, einfach erweitert werden. Sollten einmal Ersetzungen nötig sein, können diese einfach implementiert werden ohne die Kompatibilität mit der jetzigen Version zu gefährden.&lt;/p&gt;

&lt;p&gt;Die vorgestellte Lösung stellt lediglich ein sehr einfaches Modell eines Thesaurus dar. Zudem ist diese Lösung auf die Verwendung in einer Suche zugeschnitten.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:4972dd4c-d49f-4318-9a9f-a0b82e81b2a7" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/c%23" rel="tag"&gt;c#&lt;/a&gt;,&lt;a href="http://technorati.com/tags/searching" rel="tag"&gt;searching&lt;/a&gt;,&lt;a href="http://technorati.com/tags/thesaurus" rel="tag"&gt;thesaurus&lt;/a&gt;&lt;/div&gt;

&lt;div style="margin-top: 10px; height: 15px" class="zemanta-pixie"&gt;&lt;img style="border-bottom-style: none; border-right-style: none; border-top-style: none; float: right; border-left-style: none" class="zemanta-pixie-img" alt="" src="http://img.zemanta.com/pixy.gif?x-id=305ad59b-f372-4285-a457-01d30f63476e" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/--ZU6KcLZGOC2c9WPaYc1eGpSeM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/--ZU6KcLZGOC2c9WPaYc1eGpSeM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/--ZU6KcLZGOC2c9WPaYc1eGpSeM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/--ZU6KcLZGOC2c9WPaYc1eGpSeM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=QsqIa5CVvMc:54LU3zt97Z8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=QsqIa5CVvMc:54LU3zt97Z8:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=QsqIa5CVvMc:54LU3zt97Z8:1DmhQM8_AdY"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=1DmhQM8_AdY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/klaus_b/~4/QsqIa5CVvMc" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/QsqIa5CVvMc/post.aspx</link>
      <author>klaus_b0@hotmail.de (klaus_b)</author>
      <comments>http://blog.klaus-b.net/post/2009/08/13/Ein-Thesaurus-Modell-zur-Verwendung-in-einer-Suche.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=f990c4e3-0347-4c9a-a06d-a4de7147fe17</guid>
      <pubDate>Thu, 13 Aug 2009 16:45:27 +0100</pubDate>
      <category>C#</category>
      <dc:publisher>klaus_b0@hotmail.de (klaus_b)</dc:publisher>
      <pingback:server>http://blog.klaus-b.net/pingback.axd</pingback:server>
      <pingback:target>http://blog.klaus-b.net/post.aspx?id=f990c4e3-0347-4c9a-a06d-a4de7147fe17</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=f990c4e3-0347-4c9a-a06d-a4de7147fe17</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2009/08/13/Ein-Thesaurus-Modell-zur-Verwendung-in-einer-Suche.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=f990c4e3-0347-4c9a-a06d-a4de7147fe17</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=f990c4e3-0347-4c9a-a06d-a4de7147fe17</feedburner:origLink></item>
    <item>
      <title>Eine eigene Suche für kleine Webs – Teil 7</title>
      <description>&lt;p&gt;Im &lt;a title="Eine eigene Suche für kleine Webs - Teil 6" href="http://blog.klaus-b.net/post/2009/08/03/Eine-eigene-Suche-fur-kleine-Webs-e28093-Teil-6.aspx"&gt;vorherigen Artikel&lt;/a&gt; der Reihe habe ich die bisher erstellte Suche als linear und naiv so stehen gelassen. In diesem Artikel will ich nun ein Konzept zeigen, welches einer echten Volltextsuche schon sehr nahe kommt.     &lt;br /&gt;Dazu werden zunächst einmal zwei verschiedene Container benötigt:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Ein Index welcher die Seiten des Web mit all ihren Informationen enthält. &lt;/li&gt;    &lt;li&gt;Ein Volltextkatalog der mit allen im Web vorkommenden Wörtern gefüllt ist. Dabei wird jedes Wort mit einer Liste von &lt;a title="Uniform Resource Locator" href="http://de.wikipedia.org/wiki/Uniform_Resource_Locator" rel="wiki"&gt;URLs&lt;/a&gt; verknüpft, in denen das entsprechende Wort vorkommt. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Gesucht wird jetzt nicht mehr im Index des Web, sondern im Volltextkatalog. Doch dazu gleich mehr.&lt;/p&gt;  &lt;p&gt;Um nicht die verschiedensten Schreibweißen eines Wortes indizieren zu müssen, wird jedes Wort mit Hilfe der &lt;a title="Kölner Phonetik" href="http://de.wikipedia.org/wiki/K%C3%B6lner_Phonetik" rel="wiki"&gt;Kölner Phonetik&lt;/a&gt; kodiert und in den Volltextkatalog geschrieben. So wird gewährleistet, dass auch jede phonetische Ähnlichkeit in nur einem Datensatz gespeichert wird. Wie der Algorithmus der Kölner Phonetik in .NET verwendet werden kann, habe ich in &lt;a href="http://blog.klaus-b.net/post/2009/08/06/Verwendung-der-Kolner-Phonetik-in-NET.aspx"&gt;diesem Artikel&lt;/a&gt; schon einmal erläutert.     &lt;br /&gt;Es macht allerdings keinen Sinn, jedes mögliche Wort zu kodieren. Also muss ein Kriterium erstellt werden welches festlegt, was ein Wort ist und was nicht. Nach diesem Kriterium muss einmal bei der Erstellung der Kataloge und zum anderen bei der Analyse der Zeichenfolgen aus der Suchmaske unterschieden werden. Zur Unterscheidung eines “echten” Wort von Pseudowörtern wie etwa einer Formel oder einer anderen Abkürzung, habe ich mir folgende Kriterien überlegt:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Ein echtes Wort darf nur Buchstaben enthalten, keine Ziffern und Sonderzeichen. &lt;/li&gt;    &lt;li&gt;Es muss mindestens vier Buchstaben lang sein. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Anhand dieses Kriteriums werden zwei Wortlisten erstellt: eine für die “echten” Wörter und eine für alle vorkommenden Abkürzungen, Formeln udgl. Anschließend werden die beiden Listen entsprechen ihres Inhalts entweder kodiert oder als Klartext im Volltextkatalog gespeichert.&lt;/p&gt;  &lt;p&gt;Da in einem etwas umfangreicheren Web schnell einige Tausend verschiedene Wörter vorkommen können, muss der Zugriff auf solch einen Volltextkatalog dementsprechend schnell sein. Da bekanntlich der schnellste Zugriff bei der Abfrage eines einzelnen Element ein O(1)-Vorgang ist, muss der Katalog auch so gestaltet werden, dass die abfragende Methode ein Resultat in einem O(1)-Vorgang liefern kann. Um diese Vorgabe umzusetzen, habe ich mich für ein &lt;a title="Dictionary(TKey, TValue) Klasse" href="http://msdn.microsoft.com/xfhwa508.aspx" rel="msdn"&gt;Dictionary&amp;lt;TKey, TValue&amp;gt;&lt;/a&gt; als Kernelement für den Katalog entschieden. Da gewährleistet werden kann, dass jeder Schlüssel, in diesem Fall ein Wort, nur einmal im Dictionary vorkommt, kann die Vorgabe eines O(1)-Vorgang bei der Abfrage als erfüllt angesehen werden.     &lt;br /&gt;Wenn jetzt zum Beispiel nach der Zeichenfolge C# im Katalog gesucht wird, ist diese nur einmal enthalten und es wird sofort eine Liste der URLs zurückgegeben in denen die Zeichenfolge C# vorkommt.&lt;/p&gt;  &lt;p&gt;Bis jetzt liegt bei der Suche nach der Zeichenfolge C# nur eine Liste von URLs vor, ohne jegliche Information der Seiten welche sich hinter den URLs befinden. Dazu wird nun der Seitenindex des Web benötigt.    &lt;br /&gt;Hier verhält es sich etwas anders mit der internen Architektur. Da der Seitenindex nicht nur für die Suche verwendet wird, liegen die Daten intern in einer &lt;a title="List(T) Klasse" href="http://msdn.microsoft.com/library/6sh2ey19.aspx" rel="msdn"&gt;List&amp;lt;T&amp;gt;&lt;/a&gt; welche die Informationen einer jeden Seite in einem Objekt vom Typ &lt;em&gt;SiteEntry&lt;/em&gt; speichert. Die Struktur &lt;em&gt;SiteEntry&lt;/em&gt; habe ich bereits in früheren Artikeln, z.B.: &lt;a title="Eine eigene Suche für kleine Webs - Teil 3" href="http://blog.klaus-b.net/post/2009/07/25/Eine-eigene-Suche-fur-kleine-Webs-e28093-Teil-3.aspx"&gt;hier&lt;/a&gt;, erläutert.     &lt;br /&gt;Da die Aufzählung List&amp;lt;T&amp;gt; keine Zugriffe unterstützt die einem O(1)-Vorgang nahe kommen, habe ich mir hier mit einem kleinem Kniff beholfen. Die Klasse &lt;em&gt;SiteIndex&lt;/em&gt; bietet unter anderem einen &lt;a title="Indexer (C#)" href="http://msdn.microsoft.com/6x16t2tx.aspx" rel="msdn"&gt;Indexer&lt;/a&gt;, der eine direkten Zugriff auf das jeweilige Element am angegebenen Index zulässt. Parallel zur List&amp;lt;T&amp;gt;, welche die Seiteninformationen speichert, wird ein Dictionary geführt, welches als Schlüssel eine URL verwendet und als jeweiliger Wert wird der Index des betreffenden Elements in der List&amp;lt;T&amp;gt; gespeichert. Das ganze verhält sich ähnlich wie &lt;a title="Verzweigte Arrays" href="http://msdn.microsoft.com/2s05feca.aspx" rel="msdn"&gt;verzweigte Arrays&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;img style="display: block; float: none; margin-left: auto; margin-right: auto" title="Jagged Dictionary List" alt="Jagged Dictionary List" src="http://blog.klaus-b.net/image.axd?picture=JaggedDictionaryList.png" width="472" height="378" /&gt; &lt;/p&gt;  &lt;p&gt;Das Dictionary wird nach einer URL abgefragt und liefert den Indexwert des betreffenden &lt;em&gt;SiteEntry&lt;/em&gt;-Objekts in der List&amp;lt;T&amp;gt;. Nun wird das Objekt,dessen Index jetzt bekannt ist, direkt und ohne Iteration aus der List&amp;lt;T&amp;gt; zurückgegeben. Auf diese Art und Weiße besitzt der Seitenindex jetzt auch eine Methode, die einem O(1)-Vorgang nahe kommt.     &lt;br /&gt;Die Erstellung des parallelen Dictionary ist denkbar einfach. Wenn ein Element dem Seitenindex, also einer List&amp;lt;T&amp;gt;, hinzugefügt wird, fügt die Liste dieses Element am Ende an. Dem Dictionary kann jetzt ein Eintrag mit der aktuellen URL als Schlüssel und der Länge der List&amp;lt;T&amp;gt; –1 als Wert hinzugefügt werden.&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:c4a6ef20-a837-42af-be91-59c7bd7db7d3" class="wlWriterEditableSmartContent"&gt;&lt;pre title="code" class="c#:firstline[142]"&gt;public void Add(SiteEntry item)
{
    // prüfen ob der Eintrag noch nicht vorhanden ist
    if (!list.Contains(item))
    {
        this.list.Add(item);

		// Eintrag im Dictionary erzeugen
        this.index.Add(item.Url, this.list.Count - 1);
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Wenn ein Eintrag aus der List&amp;lt;T&amp;gt; gelöscht wird, muss das Dictionary natürlich ebenfalls aktualisiert werden.&lt;/p&gt;

&lt;p&gt;Werfen wir jetzt einen Blick auf den Ablauf einer Suche.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:098ce81f-b019-442b-b93c-2b61b433f8ac" class="wlWriterEditableSmartContent"&gt;&lt;pre title="code" class="c#:firstline[249]"&gt;// Liste welche die URLs der Ergebnisse aufnimmt.
List&amp;lt;Uri&amp;gt; uriList = new List&amp;lt;Uri&amp;gt;();

// die einzelnen Suchwörter abfragen
foreach (var word in searchTerms)
{
    // Liste für ein einzelnen Suchwort
    List&amp;lt;Uri&amp;gt; results = null;

    if (SiteSearch.IsRealWord(word))
    {
        // "echtes" Wort; kodiert suchen
        results = (List&amp;lt;Uri&amp;gt;)this.fulltextCatalog.Find(
                        ColognePhonetic.Encode(word));
    }
    else
    {
        // Abkürzung oder Formel; Klartextsuche
        results = (List&amp;lt;Uri&amp;gt;)this.fulltextCatalog.Find(word);
    }

    // prüfen ob Resultate vorliegen
    if (results == null)
    {
        continue;   // nichts gefunden
    }

    // Resultate der URL-Liste hinzufügen
    foreach (var entry in results)
    {
        if (!uriList.Contains(entry))
        {
            uriList.Add(entry);
        }
    }
}

// Liste mit den Seiten als Ergebnis zur Auswertung erzeugen
List&amp;lt;SiteEntry&amp;gt; preSelected = new List&amp;lt;SiteEntry&amp;gt;(uriList.Count);

// die Liste anhand der gefundenen URLs aus dem Seitenindex füllen
foreach (var entry in uriList)
{
    preSelected.Add(this.siteIndex.Find(entry));
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Für jedes Suchwort aus der Eingabemaske ist nur ein Zugriff als O(1)-Vorgang auf den Volltextkatalog nötig, um sofort alle relevanten URLs zum Suchwort zu erhalten. Die Zurückgegebenen URLs werden in der Liste &lt;em&gt;uriList&lt;/em&gt; gesammelt bis alle Suchwörter abgearbeitet sind. Beim übernehmen in die &lt;em&gt;uriList&lt;/em&gt; wird geprüft, ob die aktuelle URL aus dem Ergebnis bereits enthalten ist. 

  &lt;br /&gt;Anschließend wird die Liste &lt;em&gt;preSelected&lt;/em&gt; als List&amp;lt;T&amp;gt; vom Typ &lt;em&gt;SiteEntry&lt;/em&gt; erzeugt und mit den Seiten, die jeweils den URLs entsprechen, aus dem Seitenindex gefüllt. Auch hier ist jede Abfrage ein O(1)-Vorgang. 

  &lt;br /&gt;Wie man im obigen Listing sehen kann, müssen nur zwei Schleifen verwendet werden; ausgenommen der Schleife für die einzelnen Suchwörter. 

  &lt;br /&gt;Wenn es eine Möglichkeit gäbe um zwei Listen zu mergen, so dass in der resultierenden Liste jedes Element nur einmal vorkommt, könnte auch auf die Schleife in der Zeile 277 verzichtet werden. 

  &lt;br /&gt;Was jetzt noch zu tun bleibt, ist die Aus- und Bewertung der Ergebnisse. Eine Umsetzung dazu habe ich schon in &lt;a title="Eine eigene Suche für kleine Webs - Teil 6" href="http://blog.klaus-b.net/post/2009/08/03/Eine-eigene-Suche-fur-kleine-Webs-e28093-Teil-6.aspx"&gt;Teil – 6&lt;/a&gt; der Artikelreihe gezeigt.&lt;/p&gt;

&lt;p&gt;Wen mit dem .&lt;a title=".NET Framework" href="http://msdn.microsoft.com/netframework/" rel="msdn"&gt;NET-Framework&lt;/a&gt; in der Version 4.0 endlich offiziell die Parallelisierung Einzug hält, können auch längere Schleifen in ausreichend kurzer Zeit verarbeitet werden. Damit dürfte sich die Ausführungszeit einer Suche noch einmal deutlich verkürzen lassen. Vor allem die Bewertung der Resultate wird davon profitieren.&lt;/p&gt;

&lt;p&gt;Das eben vorgestellte Konzept kommt meiner Vorstellung einer Websuche schon sehr nahe. Ein paar Details müssen aber noch überarbeitet werden. Durch die Verwendung der Kölner Phonetik besitzt die Suche schon eine gewisse Fehlertoleranz. So werden z.B.: Resultate zu “shared memory” geliefert auch wenn sich vertippt wird wie etwa&amp;quot;: “sharde” anstatt “shared” oder “memmory” anstatt “memory”. Im Ergebnis wird jedoch noch nicht darauf hingewiesen. Um den Hinweis darauf umzusetzen, werde ich wohl um die Verwendung des “teuren” Algorithmus zur Berechnung der &lt;a title="Levenshtein-Distanz" href="http://de.wikipedia.org/wiki/Levenshtein-Distanz" rel="wiki"&gt;Levenshtein-Distanz&lt;/a&gt; nicht herumkommen. 

  &lt;br /&gt;Auch die Verwendung eines &lt;a title="Thesaurus" href="http://de.wikipedia.org/wiki/Thesaurus" rel="wiki"&gt;Thesaurus&lt;/a&gt; zum Umsetzen von Erweiterungslisten währe Sinnvoll. Damit könnte z.B.: bei der Eingabe von JS auch zusätzlich nach JScript oder JavaScript gesucht werden. 

  &lt;br /&gt;Die Umsetzung Thesaurus könnte ich mir in naher Zukunft vorstellen, aber für die Implementierung des Levenshtein-Algorithmus warte ich definitiv auf .NET 4.0.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:8047d310-127b-471c-8149-8fd1193846b4" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/asp.net" rel="tag"&gt;asp.net&lt;/a&gt;,&lt;a href="http://technorati.com/tags/web+search" rel="tag"&gt;web search&lt;/a&gt;,&lt;a href="http://technorati.com/tags/indexing" rel="tag"&gt;indexing&lt;/a&gt;,&lt;a href="http://technorati.com/tags/fulltext+catalog" rel="tag"&gt;fulltext catalog&lt;/a&gt;&lt;/div&gt;

&lt;div style="margin-top: 10px; height: 15px" class="zemanta-pixie"&gt;&lt;img style="border-bottom-style: none; border-right-style: none; border-top-style: none; float: right; border-left-style: none" class="zemanta-pixie-img" alt="" src="http://img.zemanta.com/pixy.gif?x-id=09b996b5-3545-4de5-9ee2-78cbbc504c69" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/fTpAtSfmTUDYxAjw9jxXukyYO-I/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/fTpAtSfmTUDYxAjw9jxXukyYO-I/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/fTpAtSfmTUDYxAjw9jxXukyYO-I/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/fTpAtSfmTUDYxAjw9jxXukyYO-I/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=PVJwoi93FR8:-FMi_4gGmCM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=PVJwoi93FR8:-FMi_4gGmCM:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=PVJwoi93FR8:-FMi_4gGmCM:1DmhQM8_AdY"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=1DmhQM8_AdY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/klaus_b/~4/PVJwoi93FR8" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/PVJwoi93FR8/post.aspx</link>
      <author>klaus_b0@hotmail.de (klaus_b)</author>
      <comments>http://blog.klaus-b.net/post/2009/08/11/Eine-eigene-Suche-fur-kleine-Webs-e28093-Teil-7.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=c98ac08a-12d3-4012-88a5-99b267f626b9</guid>
      <pubDate>Tue, 11 Aug 2009 16:01:10 +0100</pubDate>
      <category>ASP.NET</category>
      <dc:publisher>klaus_b0@hotmail.de (klaus_b)</dc:publisher>
      <pingback:server>http://blog.klaus-b.net/pingback.axd</pingback:server>
      <pingback:target>http://blog.klaus-b.net/post.aspx?id=c98ac08a-12d3-4012-88a5-99b267f626b9</pingback:target>
      <slash:comments>2</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=c98ac08a-12d3-4012-88a5-99b267f626b9</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2009/08/11/Eine-eigene-Suche-fur-kleine-Webs-e28093-Teil-7.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=c98ac08a-12d3-4012-88a5-99b267f626b9</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=c98ac08a-12d3-4012-88a5-99b267f626b9</feedburner:origLink></item>
  </channel>
</rss>
