{"id":16521,"date":"2010-11-13T00:01:00","date_gmt":"2010-11-13T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2010\/11\/13\/weekend-scripter-use-powershell-to-configure-a-huge-query-completion-system\/"},"modified":"2010-11-13T00:01:00","modified_gmt":"2010-11-13T00:01:00","slug":"weekend-scripter-use-powershell-to-configure-a-huge-query-completion-system","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/weekend-scripter-use-powershell-to-configure-a-huge-query-completion-system\/","title":{"rendered":"Weekend Scripter: Use PowerShell to Configure a Huge Query Completion System"},"content":{"rendered":"<p>&nbsp;<\/p>\n<p><b>Summary:<\/b> Learn how to use Windows PowerShell to turn a huge text file in to a query completion system, using Fast ESP 5.3 SP3. <\/p>\n<p>&nbsp;<\/p>\n<p>Microsoft Scripting Guy Ed Wilson here. Today we have another guest blogger, Dennis Whitney. Here is what Dennis has to say about himself. <\/p>\n<p>I have been programming for a long-time, starting way back when MS Basic was being used and 5&frac14; inch floppies were your storage option. Over the years, I have done many projects for many companies using several different languages: Batch files, Perl, C\/C++, ASP and VB, python, java, JavaScript and CSS, XML\/XSLT, various Linux scripting languages and now I am learning Windows PowerShell and re-learning C#. <\/p>\n<p>I now turn the keyboard over to Dennis. <\/p>\n<p>&nbsp;<\/p>\n<p>So there I was on a peaceful afternoon, coding away on my latest killer app using Microsoft Fast ESP (Enterprise Search Platform) 5.3 SP3 when my Program Manager (PM) comes in and tells me that I have to get this done for a Proof of Concept (POC) as soon as I can. Of course, he did not have to say the sooner the better. <\/p>\n<p>After decompressing the 600 megabyte (MB) source file, I was left with a 6.5 gigabyte (GB) text file, with 133 million entries. There is no way a file that size will fit into a single FAST dictionary (.aut or .ftaut) file. In my case, I had U.S. addresses and could therefore ignore &#8216;P.O. Boxes&#8217; and did not have to worry about any term weighting. So, I used the following code snippet to append each line to the appropriate file in the output file set.<\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">Write-Host -nonewline &#8220;Processing $Infile :&gt; &#8220;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">$InfileFH = [System.IO.File]::OpenText(&#8220;$Infile&#8221;)<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">while ($line = $InfileFH.ReadLine().trim().ToLower()) {<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; $row = $line.Substring(0,1)<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; $col = $line.Substring(1,1)<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; $line = &lt;Do any string manipulations to the line here&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; if ([Regex]::IsMatch($row,&#8221;[a-z]&#8221;)) {<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Outfile = Join-Path -Path $RawOutdir -ChildPath ([Regex]::replace($Outfile_Tmpl, &#8216;VALUE&#8217;, &#8220;$row&#8221;))<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Add-Content -Path &#8220;$Outfile&#8221; -Value &#8220;$line&#8221;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; }<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; elseif ([Regex]::IsMatch($row,&#8221;[0-9]&#8221;)) {<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ([Regex]::IsMatch($col,&#8221;[0-9]&#8221;)) {<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Outfile = Join-Path -Path $RawOutdir -ChildPath ([Regex]::replace($Outfile_Tmpl, &#8216;VALUE&#8217;, &#8220;$row.$col&#8221;))<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Add-Content -Path &#8220;$Outfile&#8221; -Value &#8220;$line&#8221;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Outfile = Join-Path -Path $RawOutdir -ChildPath ([Regex]::replace($Outfile_Tmpl, &#8216;VALUE&#8217;, &#8220;$row.other&#8221;))<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Add-Content -Path &#8220;$Outfile&#8221; -Value &#8220;$line&#8221;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; } else {<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Outfile = Join-Path -Path $RawOutdir -ChildPath ([Regex]::replace($Outfile_Tmpl, &#8216;VALUE&#8217;, &#8220;other&#8221;))<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Add-Content -Path &#8220;$Outfile&#8221; -Value &#8220;$line&#8221;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; # Some eye candy&#8230;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; if ((++$linecount % $linemax) -eq 0) {<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Host -nonewline &#8220;.&#8221;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; }<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Debugging if ($linecount -eq 25) { exit }<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">}<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">$InfileFH.Close()<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">$InfileFH.Dispose()<\/span><\/p>\n<p>&nbsp;<\/p>\n<p>My next step was to remove duplicates entries. To perform this feat, I used the following Windows PowerShell code.<\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">Write-Host &#8220;Unique-ifying $RawOutdir :&gt; &#8220;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">foreach ($file in (Get-Childitem $RawOutdir)) {<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">$data = (Get-Content (Join-Path -Path $RawOutdir -ChildPath $file) | Measure-Object)<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">Write-Host -nonewline &#8220;&#8216;t&#8217;t$RawOutdir\\$file line count:&gt;&#8221; $data.Count &#8220;&#8230; &#8220;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">Get-Content (Join-Path -Path $RawOutdir -ChildPath $file) | Sort-Object | Get-Unique &gt; (Join-Path -Path $UniqueOutdir -ChildPath $file)<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">$data = (Get-Content (Join-Path -Path $UniqueOutdir -ChildPath $file) | Measure-Object)<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">Write-Host &#8220;$UniqueOutdir\\$file line count:&gt;&#8221; $data.Count<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">}<\/span><\/p>\n<p>&nbsp;<\/p>\n<p>After this code completed its run, I ended up with 137 text files that ranged in size from 47 lines of text (2KB on the disk) to 4,570,060 lines of text (204MB on the disk). The total consisted of around 103 million unique items.<\/p>\n<p>My next step, was to execute the <b>makeaut<\/b> command on each file in the <i>$UniqueOutdir<\/i> directory referenced above. This FAST command is shown here. <\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">%FASTSEARCH%\/bin\/makeaut $infile $outfile &#8220;||&#8221;<\/span><\/p>\n<p>&nbsp;<\/p>\n<p>Now that we have our aut files (the result of the <b>makeaut<\/b> command), we have to set up the query completion servers to handle all this. One of the very nice features of the completion server is the concept of a branch. A branch is the method within the matcher server (which the <b>completionserver<\/b> is based on) that enables us to target a specific dictionary at query time and it is also how we can squeeze 136 dictionaries in to 12 query completion servers and run them on a single computer. In our case, we did not want to include the &#8216;other&#8217; dictionary in our query completion setup.<\/p>\n<p>One other consideration we had, was that if you examine the file sizes, the really huge monsters are all clustered in one end of the directory listing (1.0 &#8211; 1.9) and we have to make sure these guys are not under the same <b>completionserver<\/b>. (We will get to more on this in a moment.)<\/p>\n<p>To configure the QC server, start by opening <b>%FASTSEARCH%\\etc\\NodeConf.xml<\/b> in your favorite Text Editor, comment out the existing <b>completionserver<\/b> in the <b>&lt;startorder&gt;<\/b> section and add references to our query completion server set. I ended up with the following. <\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&lt;!&#8211; &lt;proc&gt;completionserver&lt;\/proc&gt; &#8211;&gt; <\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&lt;proc&gt;<b>addr_qc_0<\/b>&lt;\/proc&gt; <\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&lt;proc&gt;<b>addr_qc_1<\/b>&lt;\/proc&gt; <\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&lt;proc&gt;<b>addr_qc_2<\/b>&lt;\/proc&gt; <\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&lt;proc&gt;<b>addr_qc_3<\/b>&lt;\/proc&gt; <\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&lt;proc&gt;<b>addr_qc_4<\/b>&lt;\/proc&gt; <\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&lt;proc&gt;<b>addr_qc_5<\/b>&lt;\/proc&gt; <\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&lt;proc&gt;<b>addr_qc_6<\/b>&lt;\/proc&gt; <\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&lt;proc&gt;<b>addr_qc_7<\/b>&lt;\/proc&gt; <\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&lt;proc&gt;<b>addr_qc_8<\/b>&lt;\/proc&gt; <\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&lt;proc&gt;<b>addr_qc_9<\/b>&lt;\/proc&gt; <\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&lt;proc&gt;<b>addr_qc_10<\/b>&lt;\/proc&gt; <\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&lt;proc&gt;<b>addr_qc_11<\/b>&lt;\/proc&gt; <\/span><\/p>\n<p>&nbsp;<\/p>\n<p>Next, we comment out the existing completion server definition in the process definition section and using the xml snippet below as a template, add the process definitions for each new <b>&lt;proc&gt;<\/b> referenced above:<\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&lt;!&#8211; Address Query Completion Server XX &#8211;&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&lt;process name=&#8221;<b>addr_qc_XX<\/b>&#8221; description=&#8221;<b>Addr QC Server XX<\/b>&#8221; multi=&#8221;<b>no<\/b>&#8220;&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&lt;start&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp; &lt;executable&gt;<b>matcherserver<\/b>&lt;\/executable&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;parameters&gt;<b>-m $FASTSEARCH\/etc\/resources\/matching\/qcaddr-groupXX.xml -f javascript -e -p $PORT -w $FASTSEARCH\/www\/matcherserver<\/b>&lt;\/parameters&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;port base=&#8221;<b>&lt;PORT&gt;<\/b>&#8221; increment=&#8221;<b>3<\/b>&#8221; count=&#8221;<b>1<\/b>&#8221; \/&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp; &lt;\/start&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp; &lt;stop&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;timeout&gt;<b>5<\/b>&lt;\/timeout&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;timeout_action&gt;<b>kill<\/b>&lt;\/timeout_action&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp; &lt;\/stop&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp; &lt;outfile&gt;<b>addr_completionserver_XX.scrap<\/b>&lt;\/outfile&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&lt;\/process&gt;<\/span><\/p>\n<p>&nbsp;<\/p>\n<p>Where <i>XX<\/i> is the number in the <b>&lt;proc&gt;<\/b> you are configuring for.<\/p>\n<p>Please note the port number is set using: 2200 + ( 5 * <i>XX<\/i>) and we should end up using port numbers 2200 &#8211; 2255<\/p>\n<p>My next step was to create the <b>$FASTSEARCH\/etc\/resources\/matching\/qcaddr-groupXX.xml <\/b>files I referenced in the process definitions. As mentioned earlier, I also have to make sure that no single query completion server was responsible for all the very large dictionaries. To do this, we used the summed ASCII values of the characters in the file name and used modulo 12 to tell us where the dictionaries should be stored and we ended up with configuration skeleton that looked like:<\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&lt;configuration&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;matcher type= &#8220;dispatcher&#8221; debug= &#8220;no&#8221; verbose=&#8221;no&#8221;&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;dispatcher&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!&#8211; &#8216;&lt;foo&gt;&#8217; dictionary configuration &#8211;&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;branch condition=&#8221;&lt;foo&gt;&#8221;&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;matcher type=&#8221;completion&#8221; debug=&#8221;no&#8221; limited=&#8221;no&#8221;&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;completion automaton = &#8220;resources\/dictionaries\/matching\/dictionary_&lt;foo&gt;.aut&#8221;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; results = &#8220;10&#8221; candidates = &#8220;100&#8221; spread = &#8220;yes&#8221; sort = &#8220;yes&#8221; lowercase = &#8220;no&#8221; cache = &#8220;yes&#8221;&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;scoring&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;length coefficient = &#8220;1.0&#8221; exponent = &#8220;1.0&#8221;\/&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;frequency coefficient = &#8220;1.0&#8221; exponent = &#8220;1.0&#8221;\/&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;\/scoring&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;\/completion&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;\/matcher&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;\/branch&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;\/dispatcher&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp; &lt;\/matcher&gt;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&lt;\/configuration&gt;<\/span><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;Repeatedly updating <b>&lt;foo&gt;<\/b> to match the modulo values I derived earlier.<\/p>\n<p>All right, I have the processes setup, configured and the .aut files created. If I did everything right, my last steps on the ESP side should be to turn it on and test it. What you want to do and see at the command line is shown here in the following figure:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0334.WES-11-13-10-01.jpg\" border=\"0\" \/>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>If everything went well here and there are no reported warnings at <strong>http:\/\/&lt;yourserver&gt;:16000\/admin\/logs\/ <\/strong>folder, your next step is to test it. I used this Windows PowerShell script to perform the testing.<\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">$url=&#8221;http:\/\/&lt;your qc server&gt;:&lt;your port&gt;\/search?q=&lt;your term&gt;&amp;c=&lt;your context&gt;&#8221;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">$output=&#8221;.\\output.txt&#8221;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">(New-Object Net.WebClient).DownloadString(&#8220;$url&#8221;) | Set-Content -path &#8220;$output&#8221;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">if ( ! (Test-Path &#8220;$output&#8221;) ) {<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; Write-Error &#8220;Failed to download $uri to $output&#8221;<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; $(throw &#8220;Failed to download $uri to $output !&#8221;)<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; exit 1<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">}<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">Write-Host Saved $url to $output !<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-family: courier new,courier\">exit 0<\/span><\/p>\n<p>&nbsp;<\/p>\n<p>At this point, you have a working QC system and in a future post, I will explain how we connected the UI to this beast.<\/p>\n<p>That is all for today. Thank you, Dennis for sharing your time and knowledge. Join us tomorrow for another guest weekend scripter, Ben Pearce, as he talks about patching VHD&#8217;s and WIM files. <\/p>\n<p>I invite you to follow me on <a target=\"_blank\" href=\"http:\/\/bit.ly\/scriptingguystwitter\">Twitter<\/a> or <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\">Facebook<\/a>. If you have any questions, send email to me at <a target=\"_blank\" href=\"mailto:scripter@microsoft.com\">scripter@microsoft.com<\/a> or post them on the <a target=\"_blank\" href=\"http:\/\/bit.ly\/scriptingforum\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p>&nbsp;<\/p>\n<p><b>Ed Wilson, Microsoft Scripting Guy<\/b><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&nbsp; Summary: Learn how to use Windows PowerShell to turn a huge text file in to a query completion system, using Fast ESP 5.3 SP3. &nbsp; Microsoft Scripting Guy Ed Wilson here. Today we have another guest blogger, Dennis Whitney. Here is what Dennis has to say about himself. I have been programming for a [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[204,205,56,206,3,4,130,61,45],"class_list":["post-16521","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-dennis-whitney","tag-fast-esp-5-3-sp3","tag-guest-blogger","tag-query-completion-server","tag-scripting-guy","tag-scripting-techniques","tag-servers","tag-weekend-scripter","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>&nbsp; Summary: Learn how to use Windows PowerShell to turn a huge text file in to a query completion system, using Fast ESP 5.3 SP3. &nbsp; Microsoft Scripting Guy Ed Wilson here. Today we have another guest blogger, Dennis Whitney. Here is what Dennis has to say about himself. I have been programming for a [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/16521","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=16521"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/16521\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=16521"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=16521"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=16521"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}