<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>mitcho.com &#187; order</title>
	<atom:link href="http://mitcho.com/blog/tag/order/feed/" rel="self" type="application/rss+xml" />
	<link>http://mitcho.com</link>
	<description></description>
	<lastBuildDate>Tue, 07 Sep 2010 03:38:57 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Scoring for Optimization</title>
		<link>http://mitcho.com/blog/observation/scoring-for-optimization/</link>
		<comments>http://mitcho.com/blog/observation/scoring-for-optimization/#comments</comments>
		<pubDate>Fri, 24 Apr 2009 09:51:31 +0000</pubDate>
		<dc:creator>mitcho</dc:creator>
				<category><![CDATA[observation]]></category>
		<category><![CDATA[algorithm]]></category>
		<category><![CDATA[candidates]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[harmonic analysis]]></category>
		<category><![CDATA[math]]></category>
		<category><![CDATA[Mozilla Planet]]></category>
		<category><![CDATA[order]]></category>
		<category><![CDATA[parser]]></category>
		<category><![CDATA[ranking]]></category>
		<category><![CDATA[score]]></category>
		<category><![CDATA[suggestions]]></category>
		<category><![CDATA[ubiquity]]></category>

		<guid isPermaLink="false">http://mitcho.com/blog/?p=1850</guid>
		<description><![CDATA[Suppose you have a number of competing candidates, each of which can be ranked with a score, but it takes a little time to calculate each candidate&#8217;s score. You&#8217;re only interested in the top candidates. You want to come up with a scoring scheme where you can throw the extra candidates out of consideration earlier [...]


Related posts:<ol><li><a href='http://mitcho.com/blog/observation/scoring-and-ranking-suggestions/' rel='bookmark' title='Permanent Link: Scoring and Ranking Suggestions'>Scoring and Ranking Suggestions</a></li>
<li><a href='http://mitcho.com/blog/projects/judging-noun-types/' rel='bookmark' title='Permanent Link: Judging Noun Types'>Judging Noun Types</a></li>
<li><a href='http://mitcho.com/blog/projects/ubiquity-parser-the-next-generation-demo/' rel='bookmark' title='Permanent Link: Ubiquity Parser: The Next Generation Demo'>Ubiquity Parser: The Next Generation Demo</a></li>
</ol>

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>Suppose you have a number of competing candidates, each of which can be ranked with a score, but it takes a little time to calculate each candidate&#8217;s score. You&#8217;re only interested in the top <img src='http://s.wordpress.com/latex.php?latex=n&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n' title='n' class='latex' /> candidates. <strong>You want to come up with a scoring scheme where you can throw the extra candidates out of consideration earlier without sacrificing quality.</strong> Such is <a href="http://mitcho.com/blog/observation/scoring-and-ranking-suggestions/">the problem of scoring and ranking suggestions in Ubiquity</a>. What properties must such a scoring system have?</p>

<p><em>This blog post includes a lot of complex CSS-formatted graphs which may be best viewed in — what else? — <a href="http://mozilla.com">Firefox</a>. You may also want to <a href="http://mitcho.com/blog/observation/scoring-for-optimization/">access this blog post directly</a> rather than through a planet.</em></p>

<p><style type='text/css'>
.mitchostable, .mitchostable tr, .mitchostable td, .mitchostable th {
  border:0;
  margin:0;
  padding:1px;
  background-color: transparent;
  text-align:left;
}
tr.cutoff th, tr.cutoff td { border-bottom: 1px #666 solid }
tr.cutoff td.cutoff {
  font-style: italic;
  font-size: 0.8em;
  color: #666;
  border: 0;
}
.mitchostable img { height: 7px }
.mitchostable span.bar { 
  background-color: #ccc;
  display: inline-block;
  height: 7px;
}
.mitchostable span.arrow-right { 
  background: #ccc url(http://mitcho.com/i/cccarrow-right.png) no-repeat scroll center right;
  display: inline-block;
  height: 7px;
}
.mitchostable span.arrow-left { 
  background: #ccc url(http://mitcho.com/i/cccarrow-left.png) no-repeat scroll center left;
  display: inline-block;
  height: 7px;
}
.mitchostable span.bound-right { 
  background: transparent url(http://mitcho.com/i/bound-right.png) no-repeat scroll center right;
  display: inline-block;
  height: 7px;
}
.mitchostable.threshold {
  background: transparent url(http://mitcho.com/i/000.png) repeat-y scroll 180px 0px;
}
.mitchostable.threshold2 {
  background: transparent url(http://mitcho.com/i/000.png) repeat-y scroll 70px 0px;
}
.mitchostable.threshold *, .mitchostable.threshold2 * {
  background: transparent;
}</p>

<p></style></p>

<table border='0' class='mitchostable'>

<tr><th>candidate 8</th><td><span class='bar' style='width:180px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>candidate 2</th><td><span class='bar' style='width:166px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>candidate 9</th><td><span class='bar' style='width:123px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>candidate 3</th><td><span class='bar' style='width:107px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr class='cutoff'><th>candidate 10</th><td><span class='bar' style='width:96px'>&nbsp;</span></td><td rowspan='2' class='cutoff'>CUTOFF</td></tr>

<tr><th>candidate 5</th><td><span class='bar' style='width:70px'>&nbsp;</span></td></tr>
<tr><th>candidate 1</th><td><span class='bar' style='width:50px'>&nbsp;</span></td></tr>
<tr><th>candidate 7</th><td><span class='bar' style='width:43px'>&nbsp;</span></td></tr>
<tr><th>&#8230;</th><td>&nbsp;</td><td>&nbsp;</td></tr>
</table>

<p>One portion of the problem description above merits clarification: I define &#8220;without sacrificing quality&#8221; to mean that, if we did not throw out any candidates early and waited until all the scores are computed fully and accurately, we would still yield the same top <img src='http://s.wordpress.com/latex.php?latex=n&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n' title='n' class='latex' /> winners. This already gives us the key insight towards an appropriate solution: <em>we can only throw out candidates when we know that it has no further chance of making it up into top <img src='http://s.wordpress.com/latex.php?latex=n&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n' title='n' class='latex' /> candidates.</em></p>

<p><span id="more-1850"></span></p>

<h3>Let&#8217;s get formal</h3>

<p>Let&#8217;s call <img src='http://s.wordpress.com/latex.php?latex=S_%7Bi%7D%28t%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='S_{i}(t)' title='S_{i}(t)' class='latex' /> the score of candidate <img src='http://s.wordpress.com/latex.php?latex=C_%7Bi%7D&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='C_{i}' title='C_{i}' class='latex' /> at time <img src='http://s.wordpress.com/latex.php?latex=t&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='t' title='t' class='latex' /> in the derivation and we&#8217;ll assume that the score derivations are done in parallel with a unique origin (<img src='http://s.wordpress.com/latex.php?latex=t%3D0&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='t=0' title='t=0' class='latex' />).<sup id="fnref:2"><a href="#fn:2" rel="footnote">1</a></sup> We&#8217;ll use the notation <img src='http://s.wordpress.com/latex.php?latex=S_%7Bi%7D%28%5Cinfty%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='S_{i}(\infty)' title='S_{i}(\infty)' class='latex' /> to represent the equilibrium or final score, equal to <img src='http://s.wordpress.com/latex.php?latex=S_%7Bi%7D%28t%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='S_{i}(t)' title='S_{i}(t)' class='latex' /> for all <img src='http://s.wordpress.com/latex.php?latex=t%20%3E%20&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='t &gt; ' title='t &gt; ' class='latex' /> a certain <img src='http://s.wordpress.com/latex.php?latex=t%5E%7B%5Cprime%7D&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='t^{\prime}' title='t^{\prime}' class='latex' /> which exists for each candidate. This function <img src='http://s.wordpress.com/latex.php?latex=S_%7Bi%7D&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='S_{i}' title='S_{i}' class='latex' /> thus defines a <a href="http://en.wikipedia.org/wiki/time series">time series</a> for each candidate.</p>

<p>Given a set of candidates <img src='http://s.wordpress.com/latex.php?latex=%5Cleft%5C%7BC_1%2CC_2%2C%5Cldots%2CC_k%5Cright%5C%7D&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\left\{C_1,C_2,\ldots,C_k\right\}' title='\left\{C_1,C_2,\ldots,C_k\right\}' class='latex' />, we want to find the best subset of <img src='http://s.wordpress.com/latex.php?latex=n&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n' title='n' class='latex' /> candidates; that is, <img src='http://s.wordpress.com/latex.php?latex=%5Cleft%5C%7BC_%7Bi_1%7D%2CC_%7Bi_2%7D%2C%5Cldots%2CC_%7Bi_n%7D%5Cright%5C%7D&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\left\{C_{i_1},C_{i_2},\ldots,C_{i_n}\right\}' title='\left\{C_{i_1},C_{i_2},\ldots,C_{i_n}\right\}' class='latex' /> such that</p>

<p><center><img src='http://s.wordpress.com/latex.php?latex=%5Cdisplaystyle%20%5Cforall_%7B%20i%5Cin%20%5C%7Bi_1%2C%5Cdots%2Ci_n%5C%7D%2C%20j%5Cin%20%5C%7B1%2C%5Cdots%2Ck%5C%7D%5Csetminus%5C%7Bi_1%2C%5Cldots%2Ci_n%5C%7D%7D%20S_%7Bi%7D%28%5Cinfty%29%20%5Cgeq%20S_%7Bj%7D%28%5Cinfty%29&#038;bg=ffffff&#038;fg=000000&#038;s=1' alt='\forall_{ i\in \{i_1,\dots,i_n\}, j\in \{1,\dots,k\}\setminus\{i_1,\ldots,i_n\}} S_{i}(\infty) \geq S_{j}(\infty)'/>.</center></p>

<h3>Approach 1: A Threshold Model</h3>

<p>The key insight above would naturally give us what I call the threshold model. Here, we require the score sequences to be non-increasing: <img src='http://s.wordpress.com/latex.php?latex=%5Cforall_%7Bt%20%3C%20t%5E%7B%5Cprime%7D%7D%20S_%7Bi%7D%28t%29%20%3C%20S_%7Bi%7D%28t%5E%7B%5Cprime%7D%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\forall_{t &lt; t^{\prime}} S_{i}(t) &lt; S_{i}(t^{\prime})' title='\forall_{t &lt; t^{\prime}} S_{i}(t) &lt; S_{i}(t^{\prime})' class='latex' />. This way, we can naturally throw out candidates which have reached below a certain threshold <img src='http://s.wordpress.com/latex.php?latex=M&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='M' title='M' class='latex' /> (or attained a certain level of badness, you might say) which we can then be sure will never recover.</p>

<p>For example, suppose the following diagram represents the scores of five different candidates after the first four time steps of the derivation. (The full gray bar marks the initial score (<img src='http://s.wordpress.com/latex.php?latex=S_i%280%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='S_i(0)' title='S_i(0)' class='latex' />) and the arrows indicate the successive score differentials.) The vertical line marks the threshold, <img src='http://s.wordpress.com/latex.php?latex=M&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='M' title='M' class='latex' />.</p>

<table border='0' class='mitchostable threshold'>
<tr><th>candidate 1</th><td><span class='bar' style='width:130px'>&nbsp;</span><span class='arrow-left' style='width:20px'>&nbsp;</span><span class='arrow-left' style='width:13px'>&nbsp;</span><span class='arrow-left' style='width:8px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>candidate 2</th><td><span class='bar' style='width:80px'>&nbsp;</span><span class='arrow-left' style='width:50px'>&nbsp;</span><span class='arrow-left' style='width:3px'>&nbsp;</span><span class='arrow-left' style='width:20px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>candidate 3</th><td><span class='bar' style='width:110px'>&nbsp;</span><span class='arrow-left' style='width:30px'>&nbsp;</span><span class='arrow-left' style='width:27px'>&nbsp;</span><span class='arrow-left' style='width:15px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>candidate 4</th><td><span class='bar' style='width:53px'>&nbsp;</span><span class='arrow-left' style='width:20px'>&nbsp;</span><span class='arrow-left' style='width:50px'>&nbsp;</span><span class='arrow-left' style='width:15px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>candidate 5</th><td><span class='bar' style='width:114px'>&nbsp;</span><span class='arrow-left' style='width:3px'>&nbsp;</span><span class='arrow-left' style='width:3px'>&nbsp;</span><span class='arrow-left' style='width:6px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>&#8230;</th><td>&nbsp;</td><td>&nbsp;</td></tr>
</table>

<p>We can tell after four steps that candidates 2 and 4, given that the score sequences are non-increasing, have no chance to finish their derivation with a score <img src='http://s.wordpress.com/latex.php?latex=%3E%20M&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='&gt; M' title='&gt; M' class='latex' />. What is important to note, however, is that <em>candidate 4 already had no chance of beating the threshold after three steps.</em> <strong>There was no need to calculate the fourth derivation of the score of candidate 4</strong> (<img src='http://s.wordpress.com/latex.php?latex=S_%7B4%7D%284%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='S_{4}(4)' title='S_{4}(4)' class='latex' />). In other words, after three steps, we could completely take candidate 4 out of the running and after another step, take candidate 2 out of the running.</p>

<table>
<tr><td colspan='2'><img src='http://s.wordpress.com/latex.php?latex=t%3D2&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='t=2' title='t=2' class='latex' /></td><td colspan='2'><img src='http://s.wordpress.com/latex.php?latex=t%3D3&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='t=3' title='t=3' class='latex' /></td><td colspan='2'><img src='http://s.wordpress.com/latex.php?latex=t%3D4&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='t=4' title='t=4' class='latex' /></td></tr>
<tr>
<td><table border='0' class='mitchostable threshold2'>
<tr><th>C1</th><td><span class='bar' style='width:113px'>&nbsp;</span><span class='arrow-left' style='width:8px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>C2</th><td><span class='bar' style='width:83px'>&nbsp;</span><span class='arrow-left' style='width:20px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>C3</th><td><span class='bar' style='width:117px'>&nbsp;</span><span class='arrow-left' style='width:15px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>C4</th><td><span class='bar' style='width:73px'>&nbsp;</span><span class='arrow-left' style='width:15px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>C5</th><td><span class='bar' style='width:70px'>&nbsp;</span><span class='arrow-left' style='width:6px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>&#8230;</th><td>&nbsp;</td><td>&nbsp;</td></tr>
</table></td><td>→</td>
<td><table border='0' class='mitchostable threshold2'>
<tr><th>C1</th><td><span class='bar' style='width:100px'>&nbsp;</span><span class='arrow-left' style='width:13px'>&nbsp;</span><span class='arrow-left' style='width:8px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>C2</th><td><span class='bar' style='width:80px'>&nbsp;</span><span class='arrow-left' style='width:3px'>&nbsp;</span><span class='arrow-left' style='width:20px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>C3</th><td><span class='bar' style='width:90px'>&nbsp;</span><span class='arrow-left' style='width:27px'>&nbsp;</span><span class='arrow-left' style='width:15px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th><strike>C4</strike></th><td><span class='bar' style='width:23px'>&nbsp;</span><span class='arrow-left' style='width:50px'>&nbsp;</span><span class='arrow-left' style='width:15px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>C5</th><td><span class='bar' style='width:67px'>&nbsp;</span><span class='arrow-left' style='width:3px'>&nbsp;</span><span class='arrow-left' style='width:6px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>&#8230;</th><td>&nbsp;</td><td>&nbsp;</td></tr>
</table></td><td>→</td>
<td><table border='0' class='mitchostable threshold2'>
<tr><th>C1</th><td><span class='bar' style='width:80px'>&nbsp;</span><span class='arrow-left' style='width:20px'>&nbsp;</span><span class='arrow-left' style='width:13px'>&nbsp;</span><span class='arrow-left' style='width:8px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th><strike>C2</strike></th><td><span class='bar' style='width:30px'>&nbsp;</span><span class='arrow-left' style='width:50px'>&nbsp;</span><span class='arrow-left' style='width:3px'>&nbsp;</span><span class='arrow-left' style='width:20px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>C3</th><td><span class='bar' style='width:60px'>&nbsp;</span><span class='arrow-left' style='width:30px'>&nbsp;</span><span class='arrow-left' style='width:27px'>&nbsp;</span><span class='arrow-left' style='width:15px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th><strike>C4</strike></th><td>&nbsp;</td><td>&nbsp;</td></tr>
<tr><th>C5</th><td><span class='bar' style='width:64px'>&nbsp;</span><span class='arrow-left' style='width:3px'>&nbsp;</span><span class='arrow-left' style='width:3px'>&nbsp;</span><span class='arrow-left' style='width:6px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>&#8230;</th><td>&nbsp;</td><td>&nbsp;</td></tr>
</table></td><td>→</td>
</tr>
</table>

<p>This non-decreasing score approach was used in Ubiquity Parser 2 until just recently, and you can in fact still play with it on the <a href="http://mitcho.com/code/ubiquity/parser-demo/">online Ubiquity Parser TNG demo</a>. In that version, every parse started with an initial score of 1 and every score factor would be a value between 0 and 1. Every score factor was multiplied onto the previous score throughout the derivation, making it trivially non-increasing.</p>

<p><strong>The problem with this approach</strong> is how to choose a smart threshold and that, given a constant threshold, you may get a different number of results for every different candidate set (i.e. parser query). If your score indicates a meaningful value with an a priori specified target of acceptable values, having a threshold makes sense. In the case of Ubiquity, however, the interface expects a certain number of suggestions to be returned.<sup id="fnref:1"><a href="#fn:1" rel="footnote">2</a></sup> If we plan to display five suggestions but the parser only returns four, even though there were other candidates, there must be a very good reason and justification for that threshold value.</p>

<h3>Approach 2: Raising the Bar</h3>

<p>The problem with Approach 1 was that there was no way of guaranteeing that we would yield our predefined <img src='http://s.wordpress.com/latex.php?latex=n&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n' title='n' class='latex' /> winning candidates. Even if at some point in the derivation we are left with <img src='http://s.wordpress.com/latex.php?latex=n&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n' title='n' class='latex' /> candidates still above the threshold, as the only restriction we have is that our score series are non-increasing, there is still a possibility that those remaining <img src='http://s.wordpress.com/latex.php?latex=n&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n' title='n' class='latex' /> candidates&#8217; scores will drop below <img src='http://s.wordpress.com/latex.php?latex=M&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='M' title='M' class='latex' /> later in the derivation.</p>

<p>We must instead at some point in the derivation identify <strong>(a)</strong> a set of at least <img src='http://s.wordpress.com/latex.php?latex=n&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n' title='n' class='latex' /> candidates which will not get &#8220;worse&#8221; in the derivation and <strong>(b)</strong> candidates which have no chance of overtaking the (a) candidates. In this situation we can safely throw out the (b) candidates.</p>

<p>One way to do this is to require that all the scores <img src='http://s.wordpress.com/latex.php?latex=S_%7Bi%7D%28t%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='S_{i}(t)' title='S_{i}(t)' class='latex' /> are <strong>bounded and non-decreasing</strong>. By virtue of being non-decreasing, our top candidates at any point in our derivation will never get &#8220;worse&#8221; afterwards, satisfying condition (a). If relatively early in the computation we can compute a bound <img src='http://s.wordpress.com/latex.php?latex=B_i&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='B_i' title='B_i' class='latex' />, we can identify candidates which will never surpass the top candidates in group (a) above, satisfying condition (b).</p>

<p>In the example below, <img src='http://s.wordpress.com/latex.php?latex=n%3D2&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n=2' title='n=2' class='latex' /> and the thin bars mark the upper bounds <img src='http://s.wordpress.com/latex.php?latex=B_i&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='B_i' title='B_i' class='latex' />. At <img src='http://s.wordpress.com/latex.php?latex=t%3D1&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='t=1' title='t=1' class='latex' /> we can identify candidate 2 and 4 as being our top two candidates. Note that there is one candidate, candidate 5, whose upper bound <img src='http://s.wordpress.com/latex.php?latex=B_5&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='B_5' title='B_5' class='latex' /> is less than both <img src='http://s.wordpress.com/latex.php?latex=S_2%281%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='S_2(1)' title='S_2(1)' class='latex' /> and <img src='http://s.wordpress.com/latex.php?latex=S_4%281%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='S_4(1)' title='S_4(1)' class='latex' />. By definition <img src='http://s.wordpress.com/latex.php?latex=S_5%28%5Cinfty%29%20%5Cleq%20B_5&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='S_5(\infty) \leq B_5' title='S_5(\infty) \leq B_5' class='latex' /> and because the scores are non-decreasing <img src='http://s.wordpress.com/latex.php?latex=S_2%281%29%20%5Cleq%20S_2%28%5Cinfty%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='S_2(1) \leq S_2(\infty)' title='S_2(1) \leq S_2(\infty)' class='latex' /> and <img src='http://s.wordpress.com/latex.php?latex=S_4%281%29%20%5Cleq%20S_4%28%5Cinfty%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='S_4(1) \leq S_4(\infty)' title='S_4(1) \leq S_4(\infty)' class='latex' />. Therefore</p>

<p><center><img src='http://s.wordpress.com/latex.php?latex=S_5%28%5Cinfty%29%20%3C%20S_2%28%5Cinfty%29&#038;bg=ffffff&#038;fg=000000&#038;s=1' alt='S_5(\infty) < S_2(\infty)'/> and <img src='http://s.wordpress.com/latex.php?latex=S_5%28%5Cinfty%29%20%3C%20S_4%28%5Cinfty%29&#038;bg=ffffff&#038;fg=000000&#038;s=1' alt='S_5(\infty) < S_4(\infty)'/></center></p>

<p>and we can thus throw out candidate 5 at this point. By the same logic, after <img src='http://s.wordpress.com/latex.php?latex=t%3D2&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='t=2' title='t=2' class='latex' /> we can throw candidate 2 out of the running.</p>

<table>
<tr><td colspan='2'><img src='http://s.wordpress.com/latex.php?latex=t%3D1&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='t=1' title='t=1' class='latex' /></td><td colspan='2'><img src='http://s.wordpress.com/latex.php?latex=t%3D2&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='t=2' title='t=2' class='latex' /></td><td colspan='2'><img src='http://s.wordpress.com/latex.php?latex=t%3D3&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='t=3' title='t=3' class='latex' /></td></tr>
<tr>
<td><table border='0' class='mitchostable'>
<tr><th>C1</th><td><span class='bar' style='width:28px'>&nbsp;</span><span class='bound-right' style='width:70px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>C2</th><td><span class='bar' style='width:59px'>&nbsp;</span><span class='bound-right' style='width:15px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>C3</th><td><span class='bar' style='width:49px'>&nbsp;</span><span class='bound-right' style='width:40px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>C4</th><td><span class='bar' style='width:83px'>&nbsp;</span><span class='bound-right' style='width:15px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th><strike>C5</strike></th><td><span class='bar' style='width:56px'>&nbsp;</span><span class='bound-right' style='width:6px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>&#8230;</th><td>&nbsp;</td><td>&nbsp;</td></tr>
</table></td><td>→</td>
<td><table border='0' class='mitchostable'>
<tr><th>C1</th><td><span class='bar' style='width:28px'>&nbsp;</span><span class='arrow-right' style='width:56px'>&nbsp;</span><span class='bound-right' style='width:14px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th><strike>C2</strike></th><td><span class='bar' style='width:59px'>&nbsp;</span><span class='arrow-right' style='width:5px'>&nbsp;</span><span class='bound-right' style='width:10px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>C3</th><td><span class='bar' style='width:49px'>&nbsp;</span><span class='arrow-right' style='width:20px'>&nbsp;</span><span class='bound-right' style='width:20px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>C4</th><td><span class='bar' style='width:83px'>&nbsp;</span><span class='arrow-right' style='width:6px'>&nbsp;</span><span class='bound-right' style='width:9px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th><strike>C5</strike></th><td>&nbsp;</td><td>&nbsp;</td></tr>
<tr><th>&#8230;</th><td>&nbsp;</td><td>&nbsp;</td></tr>
</table></td><td>→</td>
<td><table border='0' class='mitchostable'>
<tr><th>C1</th><td><span class='bar' style='width:28px'>&nbsp;</span><span class='arrow-right' style='width:56px'>&nbsp;</span><span class='arrow-right' style='width:4px'>&nbsp;</span><span class='bound-right' style='width:10px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th><strike>C2</strike></th><td>&nbsp;</td><td>&nbsp;</td></tr>
<tr><th>C3</th><td><span class='bar' style='width:49px'>&nbsp;</span><span class='arrow-right' style='width:20px'>&nbsp;</span><span class='arrow-right' style='width:15px'>&nbsp;</span><span class='bound-right' style='width:5px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th>C4</th><td><span class='bar' style='width:83px'>&nbsp;</span><span class='arrow-right' style='width:6px'>&nbsp;</span><span class='arrow-right' style='width:6px'>&nbsp;</span><span class='bound-right' style='width:3px'>&nbsp;</span></td><td>&nbsp;</td></tr>
<tr><th><strike>C5</strike></th><td>&nbsp;</td><td>&nbsp;</td></tr>
<tr><th>&#8230;</th><td>&nbsp;</td><td>&nbsp;</td></tr>
</table></td><td>→</td>
</tr>
</table>

<p>Calling this the &#8220;raising the bar&#8221; method refers to the fact that, at any particular time <img src='http://s.wordpress.com/latex.php?latex=t&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='t' title='t' class='latex' />, the &#8220;bar&#8221; is <img src='http://s.wordpress.com/latex.php?latex=min%5Cleft%28%5Cleft%5C%7B%5Cmbox%7Bthe%20%7Dn%5Cmbox%7B%20greatest%20%7DS_%7Bi%7D%28t%29%5Cmbox%7B%20values%7D%5Cright%5C%7D%5Cright%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='min\left(\left\{\mbox{the }n\mbox{ greatest }S_{i}(t)\mbox{ values}\right\}\right)' title='min\left(\left\{\mbox{the }n\mbox{ greatest }S_{i}(t)\mbox{ values}\right\}\right)' class='latex' /> and every other candidate must have an upper bound <img src='http://s.wordpress.com/latex.php?latex=B_j&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='B_j' title='B_j' class='latex' /> greater than the bar in order to not be thrown out of consideration. This &#8220;bar&#8221; itself is, together with the component scores, non-decreasing, decreasing the number of surviving candidates over time.</p>

<p>In the case of <a href="http://mitcho.com/blog/projects/a-demonstration-of-ubiquity-parser-2/">the Ubiquity parser</a> we could build such a non-decreasing and bounded scoring model by using an additive model. As the main component of parser scoring is <a href="https://ubiquity.mozilla.com/trac/ticket/435">how well the parsed arguments match the verbs&#8217; specified nountypes</a>, we could simply add up all the confidence scores of each nountype suggestion, each of which are a value between 0 and 1. This would trivially be non-decreasing. As each parse has a finite and known number of parsed arguments, we could easily determine a bound as well. For example, say a parse <img src='http://s.wordpress.com/latex.php?latex=S_0&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='S_0' title='S_0' class='latex' /> has two arguments. Before we check each of the nountypes&#8217; match scores, we already know that <img src='http://s.wordpress.com/latex.php?latex=S_0%28%5Cinfty%29%20%5Cleq%202%20%3D%20B_0&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='S_0(\infty) \leq 2 = B_0' title='S_0(\infty) \leq 2 = B_0' class='latex' />.</p>

<p>Unfortunately, there are also other factors which we would like to consider in our parses which may not fit into this non-decreasing model so easily&#8230;</p>

<h3>Approach 2&#8217;: The Rising Sun Model<sup id="fnref:3"><a href="#fn:3" rel="footnote">3</a></sup></h3>

<p>One problem with both of the previous approaches is that it requires that the scoring schemes be either non-increasing or non-decreasing across the derivation. There are many situations, however, where you would want different factors to affect the score both positively and negatively. In the case of the Ubiquity parser, here are some different factors which could be good positive and negative score factors in computing the score of each parse.</p>

<table>
<tr><th>positive factors</th><th>negative factors</th></tr>
<tr><td>the verb&#8217;s specified nountype matching the argument noun well</td><td>having to suggest the verb</td></tr>
<tr><td>the verb in the input matching the verb well</td><td>multiple arguments parsed for a single <a href='http://mitcho.com/blog/projects/writing-commands-with-semantic-roles/'>semantic role</a></td></tr>
<tr><td>the verb being used often</td><td>the verb missing some arguments</td></tr>
</table>

<p>As we see, there are both positive and negative factors which we hope to consider in scoring our possible Ubiquity parses. They key to making this work is by noting that Approach 2 only requires that the scoring series be bounded and non-decreasing <em>after a certain known time in the derivation</em>. For example, even if a parse involves a number of decreases early in the parse derivation, if after a certain point we can be certain that it is non-decreasing and bounded, we can simply use that bound and start eliminating poor candidates at that time (in this example, after <img src='http://s.wordpress.com/latex.php?latex=t%3D2&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='t=2' title='t=2' class='latex' />).</p>

<p><style type='text/css'>
.mitchostable2, .mitchostable2 tr, .mitchostable2 td, .mitchostable2 th {
  border:0;
  margin:0;
  padding:1px;
  text-align:left;
  vertical-align: bottom;
}
.mitchostable2 {
  background: transparent url(http://mitcho.com/i/000.png) repeat-x 0px 57px;
}
.mitchostable2 * {
  background: transparent;
}
.mitchostable2 span.bar { 
  background-color: #ccc;
  display: inline-block;
  width: 7px;
}
</style></p>

<table border='0' class='mitchostable2'>
<tr>
<td><span class='bar' style='height:150px'>&nbsp;</span></td><td><span class='bar' style='height:120px'>&nbsp;</span></td><td><span class='bar' style='height:90px'>&nbsp;</span></td><td><span class='bar' style='height:50px'>&nbsp;</span></td><td><span class='bar' style='height:60px'>&nbsp;</span></td><td><span class='bar' style='height:72px'>&nbsp;</span></td><td><span class='bar' style='height:80px'>&nbsp;</span></td><td><span class='bar' style='height:82px'>&nbsp;</span></td><td><span class='bar' style='height:90px'>&nbsp;</span></td><td><span class='bar' style='height:92px'>&nbsp;</span></td><td><span class='bar' style='height:92px'>&nbsp;</span></td><td><span class='bar' style='height:93px'>&nbsp;</span></td><td><span class='bar' style='height:93px'>&nbsp;</span></td><td><span class='bar' style='height:94px'>&nbsp;</span></td>
</tr>
<tr><td>0</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>5</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td colspan="3">10</td><td>&nbsp;</td></tr>
</table>

<p>This is very much possible in the Ubiquity parser as, given the <a href="https://wiki.mozilla.org/User:Mitcho/ParserTNG">Ubiquity Parser 2 design</a>, the negative factors such as whether the parse has a verb from the input or not (step 2), whether multiple arguments are identified with the same semantic role (step 4), and how many of the verb&#8217;s arguments are in the input (step 4) can be identified early on in the derivation, all before the very computationally intensive step of nountype detection (step 7) and argument suggestion (step 8). In this way, we can front-load all the negative factors in scoring and continue to use a version of Approach 2 to optimize our parsing.</p>

<p>We can moreover make the effect of the negative factors be felt across the entire derivation by figuring the negative factors into a factor between 0 and 1 and multiplying it onto each of the positive factors being added. In other words, we can compute all the negative factors into a single <strong>score multiplier</strong> <img src='http://s.wordpress.com/latex.php?latex=%5Cmu_i%20%5Cin%20%5B0%2C1%5D&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\mu_i \in [0,1]' title='\mu_i \in [0,1]' class='latex' /> earlier in the derivation and then afterwards when adding up each of the positive factors simply applying that score multiplier to the score derivation:</p>

<p><center><img src='http://s.wordpress.com/latex.php?latex=%5Cmu_%7Bi%7D%28%5Cmbox%7Bpositive%20factor%200%7D%29%20%2B%20%5Cmu_%7Bi%7D%28%5Cmbox%7Bpositive%20factor%201%7D%29%20%2B%20%5Cldots%20%5Cmu_%7Bi%7D%28%5Cmbox%7Bpositive%20factor%20%7Dm%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\mu_{i}(\mbox{positive factor 0}) + \mu_{i}(\mbox{positive factor 1}) + \ldots \mu_{i}(\mbox{positive factor }m)' title='\mu_{i}(\mbox{positive factor 0}) + \mu_{i}(\mbox{positive factor 1}) + \ldots \mu_{i}(\mbox{positive factor }m)' class='latex' />.</center></p>

<p>This model is what is going on <a href="https://ubiquity.mozilla.com/hg/ubiquity-firefox/raw-file/2bc28033a723/ubiquity/index.html#modules/parser/tng/parser.js">under the hood</a> in <a href="http://mitcho.com/blog/projects/a-demonstration-of-ubiquity-parser-2/">Ubiquity Parser 2</a>. The <code>Parser.Parse</code> class has a property called <code>.scoreMultiplier</code> which contains the score multiplier <img src='http://s.wordpress.com/latex.php?latex=%5Cmu_i&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\mu_i' title='\mu_i' class='latex' /> as described above. A method called <code>.getMaxScore()</code> is implemented in addition to <code>.getScore()</code> so that, even before all of the nountype suggestion scores have been computed (e.g., in the case of asynchronous suggestions) <code>.getMaxScore()</code> can be used as an upper bound <img src='http://s.wordpress.com/latex.php?latex=B_i&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='B_i' title='B_i' class='latex' /> and compared to the in-progress scores of other candidates and lower candidates can thus be taken out of consideration earlier in the parse process.</p>

<h3>Conclusion</h3>

<p>In this blog post I&#8217;ve laid out a few different iterations of approaches I&#8217;ve thought of on the problem of scoring and ranking Ubiquity suggestions in a smart way. While some of the basic mechanisms of front-loading the negative factors into a <code>scoreMultiplier</code> and the computation of the <code>maxScore</code> (or upper bound) have been implemented, the actual optimization algorithm described here of removing parses from consideration earlier in the parser query has yet to be implemented in Ubiquity Parser 2 and I look forward to seeing it in action. In addition, there are surely factors I haven&#8217;t considered in the scoring or further tricks to improve the optimized scoring algorithm. <strong>I&#8217;d love to get your feedback and ideas on this topic.</strong> Thanks!</p>

<div class="footnotes">
<hr />
<ol>

<li id="fn:2">
<p>In the case of Ubiquity Parser 2, we&#8217;ll let the &#8220;time&#8221; values <img src='http://s.wordpress.com/latex.php?latex=t&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='t' title='t' class='latex' /> refer to the &#8220;steps&#8221; in the derivation, as laid out in <a href="https://wiki.mozilla.org/User:Mitcho/ParserTNG">the Ubiquity Parser 2 design</a>. Note that these &#8220;steps&#8221; are currently done in parallel across all candidates in the current architecture, making the &#8220;time&#8221; analogy legitimate. I will thus use integer time values here, making this a <a href="http://en.wikipedia.org/wiki/discrete-time">discrete-time</a> model.&#160;<a href="#fnref:2" rev="footnote">&#8617;</a></p>
</li>

<li id="fn:1">
<p>Every Ubiquity parser query takes as a parameter the maximum number of suggestions to be returned. See <a href="https://ubiquity.mozilla.com/trac/ticket/532">the latest parser query interface proposal</a> for details on this interface.&#160;<a href="#fnref:1" rev="footnote">&#8617;</a></p>
</li>

<li id="fn:3">
<p>This naming is an homage to the <a href="http://en.wikipedia.org/wiki/rising sun lemma">rising sun lemma</a> of <a href="http://en.wikipedia.org/wiki/Frigyes Riesz">Frigyes Riesz</a> which uses a similar logic. The apparent connection to the fact that I am Japanese is purely coincidental.&#160;<a href="#fnref:3" rev="footnote">&#8617;</a></p>
</li>

</ol>
</div>


<p>Related posts:<ol><li><a href='http://mitcho.com/blog/observation/scoring-and-ranking-suggestions/' rel='bookmark' title='Permanent Link: Scoring and Ranking Suggestions'>Scoring and Ranking Suggestions</a></li>
<li><a href='http://mitcho.com/blog/projects/judging-noun-types/' rel='bookmark' title='Permanent Link: Judging Noun Types'>Judging Noun Types</a></li>
<li><a href='http://mitcho.com/blog/projects/ubiquity-parser-the-next-generation-demo/' rel='bookmark' title='Permanent Link: Ubiquity Parser: The Next Generation Demo'>Ubiquity Parser: The Next Generation Demo</a></li>
</ol></p>
<p>Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://mitcho.com/blog/observation/scoring-for-optimization/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Scoring and Ranking Suggestions</title>
		<link>http://mitcho.com/blog/observation/scoring-and-ranking-suggestions/</link>
		<comments>http://mitcho.com/blog/observation/scoring-and-ranking-suggestions/#comments</comments>
		<pubDate>Tue, 07 Apr 2009 07:17:26 +0000</pubDate>
		<dc:creator>mitcho</dc:creator>
				<category><![CDATA[observation]]></category>
		<category><![CDATA[algorithm]]></category>
		<category><![CDATA[candidates]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[constraints]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[linguistics]]></category>
		<category><![CDATA[Mozilla Planet]]></category>
		<category><![CDATA[Optimality Theory]]></category>
		<category><![CDATA[order]]></category>
		<category><![CDATA[parser]]></category>
		<category><![CDATA[ranking]]></category>
		<category><![CDATA[score]]></category>
		<category><![CDATA[suggestions]]></category>
		<category><![CDATA[ubiquity]]></category>

		<guid isPermaLink="false">http://mitcho.com/blog/?p=1745</guid>
		<description><![CDATA[I just spent some time reviewing how Ubiquity currently ranks its suggestions in relation to to Parser The Next Generation so I thought I&#8217;d put some of these thoughts down in writing. The issue of ranking Ubiquity suggestions can be restated as predicting an optimal output given a certain input and various conflicting considerations. Ubiquity [...]


Related posts:<ol><li><a href='http://mitcho.com/blog/observation/scoring-for-optimization/' rel='bookmark' title='Permanent Link: Scoring for Optimization'>Scoring for Optimization</a></li>
<li><a href='http://mitcho.com/blog/projects/judging-noun-types/' rel='bookmark' title='Permanent Link: Judging Noun Types'>Judging Noun Types</a></li>
<li><a href='http://mitcho.com/blog/projects/ubiquity-parser-the-next-generation-demo/' rel='bookmark' title='Permanent Link: Ubiquity Parser: The Next Generation Demo'>Ubiquity Parser: The Next Generation Demo</a></li>
</ol>

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>I just spent some time reviewing how Ubiquity currently ranks its suggestions in relation to to <a href="https://wiki.mozilla.org/User:Mitcho/ParserTNG">Parser The Next Generation</a> so I thought I&#8217;d put some of these thoughts down in writing.</p>

<p>The issue of ranking Ubiquity suggestions can be restated as predicting an optimal output given a certain input and various conflicting considerations. Ubiquity (1.8, as of this writing) computes four &#8220;scores&#8221; for each suggestion:</p>

<p><span id="more-1745"></span></p>

<ol>
<li><code>duplicateDefaultMatchScore</code>: 100 by default—lowered if an unused argument gets multiple suggestions (in <a href="https://ubiquity.mozilla.com/hg/ubiquity-firefox/file/0aaeae361c33/ubiquity/modules/parser/parser.js#l558">the words of the code</a>: &#8220;reduce the match score so that multiple entries with the same verb are only shown if there are no other verbs.&#8221;)</li>
<li><code>frequencyMatchScore</code>: a score from the <code>suggestion memory</code> of the frequency of the suggestion&#8217;s verb, given the input verb (currently the first word) or nothing, in the case of noun-first suggestions</li>
<li><code>verbMatchScore</code>: float in [0,1]: (as described <a href="https://wiki.mozilla.org/Labs/Ubiquity/Parser_Documentation#Scoring_the_Quality_of_the_Verb_Match">here</a>)

<ul>
<li>0.75 is returned in case there it is a noun-first suggestion (by virtue of the fact that <code>String.indexOf('')==0</code>)</li>
<li>1 if the verb name is equivalent across input-output</li>
<li>in [0.75,1) if the input is a prefix of the suggestion verb name</li>
<li>in [0.5,0.75) if the input is a non-prefix substring of the suggestion verb</li>
<li>in [0.25,0.5] if the input is a prefix of one of the <code>synonyms</code></li>
<li>in [0,0.25) if the input is a non-prefix substring of one of the <code>synonyms</code></li>
</ul></li>
<li><code>argMatchScore</code>: the number of arguments with matching &#8220;specific&#8221; nountypes, where &#8220;specific&#8221; is designated by the nountype having property <code>rankLast=false</code>.</li>
</ol>

<p>With the numeric scores for each of these criteria, a partial order of suggestions is constructed using a <a href="http://en.wikipedia.org/wiki/lexicographic order">lexicographic order</a>: that is, compare candidates first using <code>duplicateDefaultMatchScore</code>, break ties using <code>frequencyMatchScore</code>, if still tied break using <code>verbMatchScore</code>, and if still tied break using <code>argMatchScore</code>. This paradigm of constraints is called &#8220;strictly ranked&#8221; and a corollary of this is that lower constraints, no matter how well you score on them, can never overcome a loss at a higher constraint. A crucial corollary of this system is that lower constraints&#8217; scores need not be computed if a higher constraint already dooms it to a lower position.<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup></p>

<h3>Ranking in The Next Generation</h3>

<p>One of the goals of <a href="https://wiki.mozilla.org/User:Mitcho/ParserTNG">Parser The Next Generation</a> is to make noun/argument-first input first-class citizens of Ubiquity, improving their suggestions in particular to the benefit of <a href="http://mitcho.com/blog/projects/ubiquity-in-firefox-japanese/">verb-final languages</a>. Arguments will be split up and tested against different noun types before a verb is even entered into the input, in which case target verbs can be ranked according to the appropriateness of the input&#8217;s arguments. As such, I believe the <code>argMatchScore</code> criteria above should either be ranked higher in a strictly ranked model or be allowed to overtake lower scores for the higher constraints in a non-strictly ranked model.</p>

<p>The <a href="https://wiki.mozilla.org/User:Mitcho/ParserTNG">Parser The Next Generation</a> proposal and <a href="http://mitcho.com/code/ubiquity/parser-demo">demo</a> currently orders using a product of various criteria&#8217;s scores, rather than a lexicographic order of strictly ranked constraints. The component factors are:</p>

<ol>
<li><code>0.5</code> for parses where the verb was suggested</li>
<li><code>0.5</code> for each extra (>1) <code>object</code> argument (essentially &#8220;unused words&#8221; in the previous parser)</li>
<li>the score of each argument against that semantic role&#8217;s target noun type</li>
<li><code>0.8</code> for each unset argument of that verb</li>
</ol>

<p>Each component score is a value in [0,1], so the score is always non-decreasing across the derivation. This offers a natural way to optimize the candidate set creation: if a possible parse ever gets a score below a magic &#8220;threshold&#8221; value, it is immediately thrown away.</p>

<p>A possible problem with the current Parser TNG scoring model is that it will implicitly hinder verbs and parses with more arguments as it could have more sub-1 noun type score factors—this consideration may be great enough that a weighted additive model should be considered over a multiplicative one.</p>

<p><strong>How do you think we can make Ubiquity&#8217;s suggestion ranking smarter? What other factors should be considered, and what factors could be left out?</strong></p>

<div class="footnotes">
<hr />
<ol>

<li id="fn:1">
<p>For all the linguists in the audience, if this sounds like <a href="http://en.wikipedia.org/wiki/Optimality Theory">Optimality Theory</a>, you would be right—there&#8217;s a little bit of <a href="http://roa.rutgers.edu/view.php3?roa=537">Prince and Smolensky (1993)</a> hanging out <a href="http://ubiquity.mozilla.com">in your browser</a>.&#160;<a href="#fnref:1" rev="footnote">&#8617;</a></p>
</li>

</ol>
</div>


<p>Related posts:<ol><li><a href='http://mitcho.com/blog/observation/scoring-for-optimization/' rel='bookmark' title='Permanent Link: Scoring for Optimization'>Scoring for Optimization</a></li>
<li><a href='http://mitcho.com/blog/projects/judging-noun-types/' rel='bookmark' title='Permanent Link: Judging Noun Types'>Judging Noun Types</a></li>
<li><a href='http://mitcho.com/blog/projects/ubiquity-parser-the-next-generation-demo/' rel='bookmark' title='Permanent Link: Ubiquity Parser: The Next Generation Demo'>Ubiquity Parser: The Next Generation Demo</a></li>
</ol></p>
<p>Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://mitcho.com/blog/observation/scoring-and-ranking-suggestions/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>External orders in WordPress queries</title>
		<link>http://mitcho.com/blog/how-to/external-orders-in-wordpress-queries/</link>
		<comments>http://mitcho.com/blog/how-to/external-orders-in-wordpress-queries/#comments</comments>
		<pubDate>Sat, 29 Nov 2008 15:34:40 +0000</pubDate>
		<dc:creator>mitcho</dc:creator>
				<category><![CDATA[how to]]></category>
		<category><![CDATA[algorithm]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[filter]]></category>
		<category><![CDATA[hook]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[order]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[query_posts]]></category>
		<category><![CDATA[ranking]]></category>
		<category><![CDATA[suggestions]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[WordPress Planet]]></category>
		<category><![CDATA[WP_Query]]></category>
		<category><![CDATA[YARPP]]></category>

		<guid isPermaLink="false">http://mitcho.com/blog/?p=1102</guid>
		<description><![CDATA[The advanced WordPress user is intimately familiar with query_posts, the function which controls which posts are displayed in &#8220;The Loop.&#8221; query_posts gives plugin and theme writers the ability to display only posts written in Janary (query_posts("monthnum=1")) or disallow posts from a certain category (query_posts("cat=-529")1). One of the parameters you can set here is orderby which [...]


Related posts:<ol><li><a href='http://mitcho.com/blog/projects/yet-another-related-posts-plugin/' rel='bookmark' title='Permanent Link: Yet Another Related Posts Plugin'>Yet Another Related Posts Plugin</a></li>
<li><a href='http://mitcho.com/blog/projects/yet-another-related-posts-plugin-20/' rel='bookmark' title='Permanent Link: Yet Another Related Posts Plugin 2.0'>Yet Another Related Posts Plugin 2.0</a></li>
<li><a href='http://mitcho.com/blog/projects/modifiying-wordpress-plugin-activation-behavior/' rel='bookmark' title='Permanent Link: Modifiying WordPress plugin activation behavior'>Modifiying WordPress plugin activation behavior</a></li>
</ol>

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>The advanced WordPress user is intimately familiar with <a href="http://codex.wordpress.org/Template_Tags/query_posts"><code>query_posts</code></a>, the function which controls which posts are displayed in &#8220;The Loop.&#8221; <code>query_posts</code> gives plugin and theme writers the ability to display only posts written in Janary (<code>query_posts("monthnum=1")</code>) or disallow posts from a certain category (<code>query_posts("cat=-529")</code><sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup>). One of the parameters you can set here is <code>orderby</code> which affects the ordering of the posts returned, with allowed values such as <code>author</code>, <code>date</code>, or <code>title</code>. But what if you want to order your posts in some other order, defined outside of your <code>wp_posts</code> table? Here I&#8217;m going to lay out some thoughts on rolling your own external ordering source for WordPress queries.</p>

<p>In order to introduce an external ordering source, we need to do four things:
1. create the external ordering source,
2. hook up (read &#8220;<code>join</code>&#8221;) the external ordering source
3. make sure we use that order, and
4. make it play nice. ^^</p>

<p>By the way, I&#8217;m going to assume you, dear reader, are PHP-savvy, proficient in MySQL, and already know a little about WordPress. This how-to is not for the PHPhobic.</p>

<p><span id="more-1102"></span></p>

<h3>The ordering source</h3>

<p>For this example, suppose we want to display posts by order of &#8220;interestingness.&#8221; We&#8217;ll just create a table called <code>wp_interestingness</code> with two columns, <code>ID</code> and <code>interestingness</code> and populate it with some data. We&#8217;ll even be nice to our database by making sure the <code>ID</code> is the primary key. Easy.</p>

<h3>Hook up the external ordering source</h3>

<p>When you run a query through <code>query_posts()</code> (or use <code>WP_Query</code>&#8217;s <code>query</code> method<sup id="fnref:2"><a href="#fn:2" rel="footnote">2</a></sup>), what it&#8217;s doing is taking your special request and translating it into a MySQL statement. This means a query like <code>"monthnum=1"</code> is turned into <code>SELECT ... wp_posts.* FROM wp_posts WHERE 1=1 AND MONTH(wp_posts.post_date)='1' ...</code>. Every different query introduces something new to the basic <code>SELECT</code> command—in this case, the <code>AND MONTH(wp_posts.post_date)='1'</code>.</p>

<p>We first want to introduce the <code>interestingness</code> for each post and that means <code>join</code>ing the new table into the query. We&#8217;ll do this using the <code>posts_join</code> <a href="http://codex.wordpress.org/Plugin_API/Filter_Reference">filter</a>. This filter lets you add a <code>join</code> statement to the MySQL request.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="php" style="font-family:monospace;">add_filter<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'posts_join'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'my_join_filter'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">function</span> my_join_filter<span style="color: #009900;">&#40;</span><span style="color: #000088;">$arg</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #000088;">$arg</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot; natural join wp_interestingness &quot;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">return</span> <span style="color: #000088;">$arg</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>


<p>Note that here we&#8217;re using <code>natural join</code> as <code>wp_posts</code> and <code>wp_interestingness</code> have only one key in common, <code>ID</code>, and that&#8217;s exactly the column we want to join them on.</p>

<h3>Use the new order</h3>

<p>Now that we&#8217;ve <code>join</code>ed <code>wp_interestingness</code> in, we can refer to <code>wp_interestingness.interestingness</code> in our query. Note now that, by default, an <code>$wpdb-&gt;posts.post_date</code> will be used to order the posts. We&#8217;ll use another filter here; this time <code>posts_orderby</code>, to patch this part of the query. We&#8217;ll search for the default <code>ORDER BY</code> value and replace it with our own <code>interestingness</code>.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="php" style="font-family:monospace;">add_filter<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'posts_orderby'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'my_orderby_filter'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">function</span> my_orderby_filter<span style="color: #009900;">&#40;</span><span style="color: #000088;">$arg</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">global</span> <span style="color: #000088;">$wpdb</span><span style="color: #339933;">;</span>
	<span style="color: #000088;">$arg</span> <span style="color: #339933;">=</span> <span style="color: #990000;">str_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;<span style="color: #006699; font-weight: bold;">$wpdb-&gt;posts</span>.post_date&quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;wp_interestingness.interestingness&quot;</span><span style="color: #339933;">,</span><span style="color: #000088;">$arg</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">return</span> <span style="color: #000088;">$arg</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>


<p>By the way, you can now check the resulting MySQL query by <code>echo</code>ing <code>$wp_query-&gt;request</code>. (If you&#8217;re using the <code>WP_Query</code> method I advocated below in footnote (2), you&#8217;ll of course have to change <code>$wp_query</code> to the <code>WP_Query</code> object you&#8217;re using.)</p>

<h3>Learn to play nice ^^</h3>

<p>The instructions above do indeed work, but they also cause some major breakdowns in other functions of your blog. Why? That&#8217;s because the current code will edit your queries for every instance of The Loop: your index page, your archives, and your RSS feeds. You probably only want to search by interestingness in certain situations. What we need is a way to tell our (admittedly stupid) <code>my_join_filter</code> and <code>my_orderby_filter</code> when they should apply their <code>interestingness</code> magic and when they shouldn&#8217;t. There are several ways to set up such a system but here I&#8217;ll lay out one that I feel is particularly elegant. We&#8217;ll set it up so you can actually use <code>query_posts("orderby=interestingness")</code> and it&#8217;ll know what you&#8217;re talking about.</p>

<p>One of the first things that happens in <code>query_posts</code>—indeed, way before even the <code>posts_join</code> and <code>posts_orderby</code> filters—is an action hook called <code>parse_query</code>. This lets us look at the initial state of the <code>WP_Query</code> object as it starts to run. In particular, we can look at the <code>orderby</code> query variable and see if we want to order by <code>interestingness</code>. If we do, we&#8217;ll set a global variable called <code>$use_interestingness_flag</code> to be <code>true</code>.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code"><pre class="php" style="font-family:monospace;">add_action<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'parse_query'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'set_use_interestingness_flag'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">function</span> set_use_interestingness_flag<span style="color: #009900;">&#40;</span><span style="color: #000088;">$query</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">global</span> <span style="color: #000088;">$use_interestingness_flag</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$query</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">query_vars</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'orderby'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'interestingness'</span><span style="color: #009900;">&#41;</span>
		<span style="color: #000088;">$yarpp_score_override</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">else</span>
		<span style="color: #000088;">$yarpp_score_override</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>


<p>Now we just have to edit our filters so they only run when <code>$use_interestingness_flag == true</code>. We also will make sure to turn the flag back off in <code>my_orderby_filter</code>, as it&#8217;s our last filter to run during each query. It&#8217;s just like putting the seat back down after using a unisex bathroom.<sup id="fnref:3"><a href="#fn:3" rel="footnote">3</a></sup></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="code"><pre class="php" style="font-family:monospace;">add_filter<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'posts_join'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'my_join_filter'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">function</span> my_join_filter<span style="color: #009900;">&#40;</span><span style="color: #000088;">$arg</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">global</span> <span style="color: #000088;">$use_interestingness_flag</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$use_interestingness_flag</span><span style="color: #009900;">&#41;</span>
		<span style="color: #000088;">$arg</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot; natural join wp_interestingness &quot;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">return</span> <span style="color: #000088;">$arg</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
add_filter<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'posts_orderby'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'my_orderby_filter'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">function</span> my_orderby_filter<span style="color: #009900;">&#40;</span><span style="color: #000088;">$arg</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">global</span> <span style="color: #000088;">$wpdb</span><span style="color: #339933;">,</span> <span style="color: #000088;">$use_interestingness_flag</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$use_interestingness_flag</span><span style="color: #009900;">&#41;</span>
		<span style="color: #000088;">$arg</span> <span style="color: #339933;">=</span> <span style="color: #990000;">str_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;<span style="color: #006699; font-weight: bold;">$wpdb-&gt;posts</span>.post_date&quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;wp_interestingness.interestingness&quot;</span><span style="color: #339933;">,</span><span style="color: #000088;">$arg</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000088;">$use_interestingness_flag</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">return</span> <span style="color: #000088;">$arg</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>


<p>This method has a great advantage as you can just set it up once and invoke it whenever you want, even together with other parameters, without any additional code. For example, you can try <code>query_posts("monthnum=1&amp;orderby=interestingness")</code> or <code>query_posts("cat=-529&amp;orderby=interestingness")</code>.</p>

<h3>Conclusion</h3>

<p>Adding an external ordering source to your WordPress post queries can be relatively straightforward if you understand what <code>query_posts</code> does and take advantage of its <a href="http://codex.wordpress.org/Plugin_API">hooks</a>. This tutorial can also serve as the basis for many other patches to <code>WP_Query</code>, not just the <code>orderby</code> parameter. To better understand the way WordPress builds its MySQL queries and the many <code>posts_*</code> filters which you can take advantage of, go to the source: <code>wp-includes/query.php</code>. Finally, you can use the special <code>parse_query</code> hook and global variables as flags to only apply the filters when necessary.</p>

<div class="footnotes">
<hr />
<ol>

<li id="fn:1">
<p>This, incidentally, is precisely what I do to hide, by default, <a href="http://twitter.com/mitchoyoshitaka/">my tweets</a> in my <code>index.php</code> and <code>archives.php</code>.&#160;<a href="#fnref:1" rev="footnote">&#8617;</a></p>
</li>

<li id="fn:2">
<p>If you&#8217;re going to get serious about rolling your WordPress queries I highly recommend you follow <a href="http://weblogtoolscollection.com/archives/2008/04/13/define-your-own-wordpress-loop-using-wp_query/">Mark Ghosh&#8217;s advice</a> on initializing another object of the <code>WP_Query</code> class and using the <code>query</code> method, rather than just using the global <code>query_posts</code> function.&#160;<a href="#fnref:2" rev="footnote">&#8617;</a></p>
</li>

<li id="fn:3">
<p>The perceptive reader will note that we are still searching for the string <code>"$wpdb-&gt;posts.post_date"</code> in <code>my_orderby_filter</code>, instead of something like <code>"$wpdb-&gt;posts.interestingness"</code>. That&#8217;s because the <code>orderby</code> value of <code>interestingness</code> is not one of the allowed <code>orderby</code> values (search for <code>$allowed_keys</code> in <code>wp-includes/query.php</code> to see the list). Thus the MySQL <code>ORDER BY</code> value is set to the default of <code>"$wpdb-&gt;posts.post_date"</code> before it gets to the <code>posts_orderby</code> filter. Now you know.&#160;<a href="#fnref:3" rev="footnote">&#8617;</a></p>
</li>

</ol>
</div>


<p>Related posts:<ol><li><a href='http://mitcho.com/blog/projects/yet-another-related-posts-plugin/' rel='bookmark' title='Permanent Link: Yet Another Related Posts Plugin'>Yet Another Related Posts Plugin</a></li>
<li><a href='http://mitcho.com/blog/projects/yet-another-related-posts-plugin-20/' rel='bookmark' title='Permanent Link: Yet Another Related Posts Plugin 2.0'>Yet Another Related Posts Plugin 2.0</a></li>
<li><a href='http://mitcho.com/blog/projects/modifiying-wordpress-plugin-activation-behavior/' rel='bookmark' title='Permanent Link: Modifiying WordPress plugin activation behavior'>Modifiying WordPress plugin activation behavior</a></li>
</ol></p>
<p>Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://mitcho.com/blog/how-to/external-orders-in-wordpress-queries/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
