{"exhaustive":{"nbHits":false,"typo":false},"exhaustiveNbHits":false,"exhaustiveTypo":false,"hits":[{"_highlightResult":{"author":{"matchLevel":"none","matchedWords":[],"value":"andsoitis"},"title":{"fullyHighlighted":false,"matchLevel":"full","matchedWords":["afterquery"],"value":"<em>AfterQuery</em> becomes Y Combinator's fastest-ever unicorn, now valued at $3.2B"},"url":{"fullyHighlighted":false,"matchLevel":"full","matchedWords":["afterquery"],"value":"https://techcrunch.com/2026/09/01/<em>afterquery</em>-reportedly-becomes-y-combinators-fastest-ever-unicorn-now-valued-at-3-2b/"}},"_tags":["story","author_andsoitis","story_49580207"],"author":"andsoitis","created_at":"2026-09-05T20:08:39Z","created_at_i":1788638919,"num_comments":0,"objectID":"49580207","points":2,"story_id":49580207,"title":"AfterQuery becomes Y Combinator's fastest-ever unicorn, now valued at $3.2B","updated_at":"2026-09-05T22:55:39Z","url":"https://techcrunch.com/2026/09/01/afterquery-reportedly-becomes-y-combinators-fastest-ever-unicorn-now-valued-at-3-2b/"},{"_highlightResult":{"author":{"matchLevel":"none","matchedWords":[],"value":"emmelaich"},"story_text":{"fullyHighlighted":false,"matchLevel":"full","matchedWords":["afterquery"],"value":"About http://<em>afterquery</em>.appspot.com/, a pure-client-side javascript tool that downloads jsonp-formatted data from a given URL, applies a configurable series of transformations, and then renders the result as either a data table or a Google Visualizations (gviz) chart."},"title":{"matchLevel":"none","matchedWords":[],"value":"Programming inside the URL string"},"url":{"matchLevel":"none","matchedWords":[],"value":"http://apenwarr.ca/log/?m=201212#18"}},"_tags":["story","author_emmelaich","story_4939674"],"author":"emmelaich","created_at":"2012-12-18T21:23:42Z","created_at_i":1355865822,"num_comments":0,"objectID":"4939674","points":6,"story_id":4939674,"story_text":"About http://afterquery.appspot.com/, a pure-client-side javascript tool that downloads jsonp-formatted data from a given URL, applies a configurable series of transformations, and then renders the result as either a data table or a Google Visualizations (gviz) chart.","title":"Programming inside the URL string","updated_at":"2026-01-13T20:29:09Z","url":"http://apenwarr.ca/log/?m=201212#18"},{"_highlightResult":{"author":{"matchLevel":"none","matchedWords":[],"value":"ChuckMcM"},"comment_text":{"fullyHighlighted":false,"matchLevel":"full","matchedWords":["afterquery"],"value":"<p><pre><code>   &gt; if you framed the issue as a business model one, not \n   &gt; a technical one, it might be a useful exercise.\n</code></pre>\nThat was kind of my point. Clearly most of the bots are trying to scrape my search engine for some specific data. I would (generally) be happy to just sell them that data rather than have them waste time trying to scrape us (that is the business model, which goes something like &quot;Hey we have a copy of the big chunk of the web on our servers, what do you want to know?&quot; but none of the bot writers seem willing to got there. They don't even send an email to ask us &quot;Hey, could we get a list of every site you've crawled that uses the following Wordpress theme?&quot; No instead they send query <em>after query</em> for &quot;/theme/xxx&quot; p=1, p=2, ... p=300.<p>On a good day I just ban their IP for a while, when I'm feeling annoyed I send them results back that are bogus. But the weird thing is you can't even start a conversation with these folks, and I suppose that would be like looters saying &quot;Well ok how about you help load this on a truck for me for 10 cents on the dollar and then your store won't be damaged.&quot; or something."},"story_title":{"matchLevel":"none","matchedWords":[],"value":"Are You a Robot? Introducing \u201cNo CAPTCHA ReCAPTCHA\u201d"},"story_url":{"matchLevel":"none","matchedWords":[],"value":"http://googleonlinesecurity.blogspot.com/2014/12/are-you-robot-introducing-no-captcha.html"}},"_tags":["comment","author_ChuckMcM","story_8693767"],"author":"ChuckMcM","children":[8696267,8696308,8708414],"comment_text":"<p><pre><code>   &gt; if you framed the issue as a business model one, not \n   &gt; a technical one, it might be a useful exercise.\n</code></pre>\nThat was kind of my point. Clearly most of the bots are trying to scrape my search engine for some specific data. I would (generally) be happy to just sell them that data rather than have them waste time trying to scrape us (that is the business model, which goes something like &quot;Hey we have a copy of the big chunk of the web on our servers, what do you want to know?&quot; but none of the bot writers seem willing to got there. They don&#x27;t even send an email to ask us &quot;Hey, could we get a list of every site you&#x27;ve crawled that uses the following Wordpress theme?&quot; No instead they send query after query for &quot;&#x2F;theme&#x2F;xxx&quot; p=1, p=2, ... p=300.<p>On a good day I just ban their IP for a while, when I&#x27;m feeling annoyed I send them results back that are bogus. But the weird thing is you can&#x27;t even start a conversation with these folks, and I suppose that would be like looters saying &quot;Well ok how about you help load this on a truck for me for 10 cents on the dollar and then your store won&#x27;t be damaged.&quot; or something.","created_at":"2014-12-03T19:53:54Z","created_at_i":1417636434,"objectID":"8695968","parent_id":8695718,"story_id":8693767,"story_title":"Are You a Robot? Introducing \u201cNo CAPTCHA ReCAPTCHA\u201d","story_url":"http://googleonlinesecurity.blogspot.com/2014/12/are-you-robot-introducing-no-captcha.html","updated_at":"2024-09-19T21:23:27Z"},{"_highlightResult":{"author":{"matchLevel":"none","matchedWords":[],"value":"johncoltrane"},"comment_text":{"fullyHighlighted":false,"matchLevel":"full","matchedWords":["afterquery"],"value":"&quot;writing a function&quot;<p><pre><code>    :help\n    (scroll a bit)\n    (find &quot;usr_41.txt Write a Vim script&quot;)\n    &lt;C-]&gt;\n    (read)\n</code></pre>\n&quot;learn about |&quot;<p><pre><code>    :h :|\n</code></pre>\n&quot;split an array in vimscript&quot; (what does that mean? &quot;splitting a string into an array&quot; or\u2026 something else?)<p><pre><code>    :h split() or if that's not what you want,\n    :h list-functions\n</code></pre>\n:h i_ctrl-w is not intuitive when you start Vim for the first time but:<p>1. it is easy to understand how it works and apply that to subsequent searches,<p>2. it is indicated in the first screen of :help.<p>So yeah, after using that search query once, it is very intuitive. Schizophrenia != intelligence + curiosity.<p>&quot;Let's say on entering a ruby file we want to press enter&quot;<p><pre><code>    :h autocmd\n    (reading)\n    autocmd BufEnter *.rb &lt;CR&gt;\n    (doesn't work)\n    (thinking)\n    (oh! &lt;CR&gt; should be a normal mode command of course!)\n    autocmd BufEnter *.rb normal &lt;CR&gt;\n    (doesn't work)\n    (oh! I remember, :normal only accepts ^M!)\n    autocmd BufEnter *.rb normal ^M\n</code></pre>\n&quot;change the background color&quot;<p><pre><code>    (look at how it's done in a random colorscheme)\n    :hi Normal guibg=#0066ff\n</code></pre>\n&quot;how to set guicursor&quot;<p><pre><code>    :h guicursor\n</code></pre>\nWhat do you want to do with your guicursor if not setting its color and/or shape and/or blinking behavior? Everything is right there.<p>Vim has a large documentation that you learn to use little by little, query <em>after query</em> but all your examples assume no prior experience with Vim's :help<p>Impatience leads nowhere.<p>---<p>By the way I <i></i>never<i></i> downvote anything: I upvote to express my agreement and I answer to express my disagreement. That, and I don't have downward triangles anyway, a consequence of my presumably low &quot;karma&quot;, maybe?"},"story_title":{"matchLevel":"none","matchedWords":[],"value":"Vim PDF Documentation"},"story_url":{"matchLevel":"none","matchedWords":[],"value":"http://nathangrigg.net/vimhelp/"}},"_tags":["comment","author_johncoltrane","story_6444165"],"author":"johncoltrane","comment_text":"&quot;writing a function&quot;<p><pre><code>    :help\n    (scroll a bit)\n    (find &quot;usr_41.txt Write a Vim script&quot;)\n    &lt;C-]&gt;\n    (read)\n</code></pre>\n&quot;learn about |&quot;<p><pre><code>    :h :|\n</code></pre>\n&quot;split an array in vimscript&quot; (what does that mean? &quot;splitting a string into an array&quot; or\u2026 something else?)<p><pre><code>    :h split() or if that&#x27;s not what you want,\n    :h list-functions\n</code></pre>\n:h i_ctrl-w is not intuitive when you start Vim for the first time but:<p>1. it is easy to understand how it works and apply that to subsequent searches,<p>2. it is indicated in the first screen of :help.<p>So yeah, after using that search query once, it is very intuitive. Schizophrenia != intelligence + curiosity.<p>&quot;Let&#x27;s say on entering a ruby file we want to press enter&quot;<p><pre><code>    :h autocmd\n    (reading)\n    autocmd BufEnter *.rb &lt;CR&gt;\n    (doesn&#x27;t work)\n    (thinking)\n    (oh! &lt;CR&gt; should be a normal mode command of course!)\n    autocmd BufEnter *.rb normal &lt;CR&gt;\n    (doesn&#x27;t work)\n    (oh! I remember, :normal only accepts ^M!)\n    autocmd BufEnter *.rb normal ^M\n</code></pre>\n&quot;change the background color&quot;<p><pre><code>    (look at how it&#x27;s done in a random colorscheme)\n    :hi Normal guibg=#0066ff\n</code></pre>\n&quot;how to set guicursor&quot;<p><pre><code>    :h guicursor\n</code></pre>\nWhat do you want to do with your guicursor if not setting its color and&#x2F;or shape and&#x2F;or blinking behavior? Everything is right there.<p>Vim has a large documentation that you learn to use little by little, query after query but all your examples assume no prior experience with Vim&#x27;s :help<p>Impatience leads nowhere.<p>---<p>By the way I <i></i>never<i></i> downvote anything: I upvote to express my agreement and I answer to express my disagreement. That, and I don&#x27;t have downward triangles anyway, a consequence of my presumably low &quot;karma&quot;, maybe?","created_at":"2013-09-27T08:07:01Z","created_at_i":1380269221,"objectID":"6455872","parent_id":6455432,"story_id":6444165,"story_title":"Vim PDF Documentation","story_url":"http://nathangrigg.net/vimhelp/","updated_at":"2024-09-19T20:02:50Z"},{"_highlightResult":{"author":{"matchLevel":"none","matchedWords":[],"value":"kragen"},"comment_text":{"fullyHighlighted":false,"matchLevel":"full","matchedWords":["afterquery"],"value":"So, aside from the Clojure, Mathematica, Python, Ruby, Bourne Shell, Haskell, and Scala solutions posted in the other comments, all of which are simpler than the C++, C#, and JS solutions, presented here with some minor cleanups:<p><pre><code>    (take 10 (reverse (sort-by (comp first rest) (frequencies (string/split ... #&quot;\\+s&quot;)))) ; llambda Clojure\n\n    // haakon Scala\n    s.split(' ').groupBy(identity).mapValues(_.size).toList.sortBy(-_._2).take(10).map(_._1)\n\n    (-&gt;&gt; (string/split s #&quot;\\s+&quot;) frequencies (sort-by val) reverse (take 10)) ; aphyr Clojure\n\n    var top = (from w in text.Split(' ')  // louthy C# LINQ\n               group w by w into g \n               orderby g.Count() descending \n               select g.Key).Take(10);\n\n    collections.Counter(s1.split()).most_common(10) # shill Python\n\n    d = {}  # shill Python without collections library\n    for word in s1.split(): d[word] = d.get(word, 0) + 1\n    print [(x, d[x]) for x in sorted(d, key=d.get, reverse=True)][:10]\n\n    words = s.split()    # spenuke and abecedarius probably O(N\u00b2) Python\n    sorted(set(words), key=words.count, reverse=True)[:10]\n\n    d3.entries((s.split(&quot; &quot;).reduce(function(p, v){  // 1wheel JS with d3\n        v in p ? p[v]++ : p[v] = 1;\n        return p;}, {})))\n      .sort(function(a, b){ return a.value &gt; b.value; })\n      .map(function(d){ return d.key;})\n      .slice(-10)\n\n    # kenuke O(N\u00b2) Ruby:\n    str.split.sort_by{|word| str.split.count(word)}.uniq.reverse.take(10)\n\n    counts = Hash.new { 0 } # my Ruby\n    str.split.each { |w| counts[w] += 1; }\n    counts.keys.sort_by { |w| -counts[w] }.take 10\n\n    # aaronbrethorst ruby\n    str.split(/\\W+/).inject(Hash.new(0)) {|acc, w| acc[w] += 1; acc}.sort {|a,b| b.last &lt;=&gt; a.last }[0,10]\n\n    Commonest[StringSplit[string], 10]  # carlob Mathematica\n\n    Reverse[SortBy[Tally[StringSplit[#]], #[[2]] &amp;]][[;; 10, 1]] &amp;  # superfx old Mathematica\n\n    $a = array_count_values(preg_split('/\\b\\s+/', $s)); arsort($a); array_slice($a, 0, 10) // Myrth PHP\n\n    tr -cs a-zA-Z '\\n' | sort | uniq -c | sort -nr | head  # mzs and me sh\n\n    -- lelf in Haskell\n    take 10 . map head . reverse . sortBy (comparing length) . group . sort . words\n\n    # prakashk Perl6\n    .say for (bag($text.words) ==&gt; sort {-*.value})[^10]\n\n    # navinp1912 C++\n     string s,f;\n     map&lt;string,int&gt; M;\n     set&lt;pair&lt;int,string&gt; &gt; S;\n     while(cin &gt;&gt; s) {\n             M[s]++;\n             int x=M[s];\n             if(x&gt;1) S.erase(make_pair(x-1,s));\n             S.insert(make_pair(x,s));\n     }\n     set&lt;pair&lt;int,string&gt; &gt;::reverse_iterator it=S.rbegin();\n     int topK=10;\n     while(topK-- &amp;&amp; (it!=S.rend())) {\n             cout &lt;&lt; it-&gt;second&lt;&lt;&quot; &quot;&lt;&lt;it-&gt;first&lt;&lt;endl;\n             it++;\n     }\n\n\n</code></pre>\nI thought I'd maybe take a look at <em>Afterquery</em>: <a href=\"http://afterquery.appspot.com/help\" rel=\"nofollow\">http://<em>afterquery</em>.appspot.com/help</a><p>Although I haven't tested it, I think the <em>Afterquery</em> program to solve this, assuming you first had something to tokenize your text into one word per row, would be something like<p><pre><code>    &amp;group=word;count(*)\n    &amp;order=-count(*)\n    &amp;limit=10\n</code></pre>\nwhich, though perhaps less readable, is simpler still, except for Mathematica.  More details at <a href=\"http://apenwarr.ca/log/?m=201212\" rel=\"nofollow\">http://apenwarr.ca/log/?m=201212</a>.<p>Perl 5, perhaps surprisingly, is not simpler:<p><pre><code>    perl -wle 'local $/; $_ = &lt;&gt;; $, = &quot; &quot;; $w{$_}++ for split; print @{[sort {$w{$b} &lt;=&gt; $w{$a}} keys %w]}[0..9]'\n</code></pre>\nAnd neither is this, although it uses less code and less RAM:<p><pre><code>    perl -wlne '$w{$_}++ for split; END { $, = &quot; &quot;; print @{[sort {$w{$b} &lt;=&gt; $w{$a}} keys %w]}[0..9]}'\n</code></pre>\nI was surprised, attempting to solve this in Common Lisp, that there's no equivalent of string/split in ANSI Common Lisp, and although SPLIT-SEQUENCE is standardized, it's not included in SBCL's default install, at least on Debian; and counting the duplicate words involves an explicit loop.  So basically in unvarnished CL you end up doing more or less what you'd do in C, but without writing your own hash table.  Lua and Scheme too, I think, except that in Scheme you don't even have hash tables."},"story_title":{"matchLevel":"none","matchedWords":[],"value":"LINQ Ruined My Favorite Interview Question"},"story_url":{"matchLevel":"none","matchedWords":[],"value":"http://scottchamberlin.tumblr.com/post/55152416452/linqinterview"}},"_tags":["comment","author_kragen","story_6025917"],"author":"kragen","children":[6031652,6032668,6032671,6032673],"comment_text":"So, aside from the Clojure, Mathematica, Python, Ruby, Bourne Shell, Haskell, and Scala solutions posted in the other comments, all of which are simpler than the C++, C#, and JS solutions, presented here with some minor cleanups:<p><pre><code>    (take 10 (reverse (sort-by (comp first rest) (frequencies (string&#x2F;split ... #&quot;\\+s&quot;)))) ; llambda Clojure\n\n    &#x2F;&#x2F; haakon Scala\n    s.split(&#x27; &#x27;).groupBy(identity).mapValues(_.size).toList.sortBy(-_._2).take(10).map(_._1)\n\n    (-&gt;&gt; (string&#x2F;split s #&quot;\\s+&quot;) frequencies (sort-by val) reverse (take 10)) ; aphyr Clojure\n\n    var top = (from w in text.Split(&#x27; &#x27;)  &#x2F;&#x2F; louthy C# LINQ\n               group w by w into g \n               orderby g.Count() descending \n               select g.Key).Take(10);\n\n    collections.Counter(s1.split()).most_common(10) # shill Python\n\n    d = {}  # shill Python without collections library\n    for word in s1.split(): d[word] = d.get(word, 0) + 1\n    print [(x, d[x]) for x in sorted(d, key=d.get, reverse=True)][:10]\n\n    words = s.split()    # spenuke and abecedarius probably O(N\u00b2) Python\n    sorted(set(words), key=words.count, reverse=True)[:10]\n\n    d3.entries((s.split(&quot; &quot;).reduce(function(p, v){  &#x2F;&#x2F; 1wheel JS with d3\n        v in p ? p[v]++ : p[v] = 1;\n        return p;}, {})))\n      .sort(function(a, b){ return a.value &gt; b.value; })\n      .map(function(d){ return d.key;})\n      .slice(-10)\n\n    # kenuke O(N\u00b2) Ruby:\n    str.split.sort_by{|word| str.split.count(word)}.uniq.reverse.take(10)\n\n    counts = Hash.new { 0 } # my Ruby\n    str.split.each { |w| counts[w] += 1; }\n    counts.keys.sort_by { |w| -counts[w] }.take 10\n\n    # aaronbrethorst ruby\n    str.split(&#x2F;\\W+&#x2F;).inject(Hash.new(0)) {|acc, w| acc[w] += 1; acc}.sort {|a,b| b.last &lt;=&gt; a.last }[0,10]\n\n    Commonest[StringSplit[string], 10]  # carlob Mathematica\n\n    Reverse[SortBy[Tally[StringSplit[#]], #[[2]] &amp;]][[;; 10, 1]] &amp;  # superfx old Mathematica\n\n    $a = array_count_values(preg_split(&#x27;&#x2F;\\b\\s+&#x2F;&#x27;, $s)); arsort($a); array_slice($a, 0, 10) &#x2F;&#x2F; Myrth PHP\n\n    tr -cs a-zA-Z &#x27;\\n&#x27; | sort | uniq -c | sort -nr | head  # mzs and me sh\n\n    -- lelf in Haskell\n    take 10 . map head . reverse . sortBy (comparing length) . group . sort . words\n\n    # prakashk Perl6\n    .say for (bag($text.words) ==&gt; sort {-*.value})[^10]\n\n    # navinp1912 C++\n     string s,f;\n     map&lt;string,int&gt; M;\n     set&lt;pair&lt;int,string&gt; &gt; S;\n     while(cin &gt;&gt; s) {\n             M[s]++;\n             int x=M[s];\n             if(x&gt;1) S.erase(make_pair(x-1,s));\n             S.insert(make_pair(x,s));\n     }\n     set&lt;pair&lt;int,string&gt; &gt;::reverse_iterator it=S.rbegin();\n     int topK=10;\n     while(topK-- &amp;&amp; (it!=S.rend())) {\n             cout &lt;&lt; it-&gt;second&lt;&lt;&quot; &quot;&lt;&lt;it-&gt;first&lt;&lt;endl;\n             it++;\n     }\n\n\n</code></pre>\nI thought I&#x27;d maybe take a look at Afterquery: <a href=\"http://afterquery.appspot.com/help\" rel=\"nofollow\">http:&#x2F;&#x2F;afterquery.appspot.com&#x2F;help</a><p>Although I haven&#x27;t tested it, I think the Afterquery program to solve this, assuming you first had something to tokenize your text into one word per row, would be something like<p><pre><code>    &amp;group=word;count(*)\n    &amp;order=-count(*)\n    &amp;limit=10\n</code></pre>\nwhich, though perhaps less readable, is simpler still, except for Mathematica.  More details at <a href=\"http://apenwarr.ca/log/?m=201212\" rel=\"nofollow\">http:&#x2F;&#x2F;apenwarr.ca&#x2F;log&#x2F;?m=201212</a>.<p>Perl 5, perhaps surprisingly, is not simpler:<p><pre><code>    perl -wle &#x27;local $&#x2F;; $_ = &lt;&gt;; $, = &quot; &quot;; $w{$_}++ for split; print @{[sort {$w{$b} &lt;=&gt; $w{$a}} keys %w]}[0..9]&#x27;\n</code></pre>\nAnd neither is this, although it uses less code and less RAM:<p><pre><code>    perl -wlne &#x27;$w{$_}++ for split; END { $, = &quot; &quot;; print @{[sort {$w{$b} &lt;=&gt; $w{$a}} keys %w]}[0..9]}&#x27;\n</code></pre>\nI was surprised, attempting to solve this in Common Lisp, that there&#x27;s no equivalent of string&#x2F;split in ANSI Common Lisp, and although SPLIT-SEQUENCE is standardized, it&#x27;s not included in SBCL&#x27;s default install, at least on Debian; and counting the duplicate words involves an explicit loop.  So basically in unvarnished CL you end up doing more or less what you&#x27;d do in C, but without writing your own hash table.  Lua and Scheme too, I think, except that in Scheme you don&#x27;t even have hash tables.","created_at":"2013-07-12T06:50:06Z","created_at_i":1373611806,"objectID":"6031272","parent_id":6025917,"story_id":6025917,"story_title":"LINQ Ruined My Favorite Interview Question","story_url":"http://scottchamberlin.tumblr.com/post/55152416452/linqinterview","updated_at":"2024-09-19T19:47:59Z"},{"_highlightResult":{"author":{"matchLevel":"none","matchedWords":[],"value":"maxerickson"},"comment_text":{"fullyHighlighted":false,"matchLevel":"full","matchedWords":["afterquery"],"value":"Have you seen <em>Afterquery</em>?<p><a href=\"http://afterquery.appspot.com/help\" rel=\"nofollow\">http://<em>afterquery</em>.appspot.com/help</a>"},"story_title":{"matchLevel":"none","matchedWords":[],"value":"R is hot [pdf]"},"story_url":{"matchLevel":"none","matchedWords":[],"value":"http://www.revolutionanalytics.com/why-revolution-r/whitepapers/R-is-Hot.pdf"}},"_tags":["comment","author_maxerickson","story_5115131"],"author":"maxerickson","children":[5115872],"comment_text":"Have you seen Afterquery?<p><a href=\"http://afterquery.appspot.com/help\" rel=\"nofollow\">http://afterquery.appspot.com/help</a>","created_at":"2013-01-25T14:27:11Z","created_at_i":1359124031,"objectID":"5115517","parent_id":5115475,"story_id":5115131,"story_title":"R is hot [pdf]","story_url":"http://www.revolutionanalytics.com/why-revolution-r/whitepapers/R-is-Hot.pdf","updated_at":"2024-09-19T19:13:52Z"},{"_highlightResult":{"author":{"matchLevel":"none","matchedWords":[],"value":"farrellh1"},"comment_text":{"fullyHighlighted":false,"matchLevel":"full","matchedWords":["afterquery"],"value":"Location: Jakarta, Indonesia (UTC+7)<p>Remote: Yes, worldwide<p>Willing to relocate: Yes, with visa sponsorship<p>Technologies: TypeScript/JavaScript, Go, Ruby, Python, Rust; \nReact, Next.js, Node.js, Rails, LangGraph; PostgreSQL, MySQL, Redis, Elasticsearch; Docker, AWS; LLM evaluation, multi-agent systems, backtesting<p>R\u00e9sum\u00e9/CV: <a href=\"https://farrellh.dev\" rel=\"nofollow\">https://farrellh.dev</a><p>GitHub: <a href=\"https://github.com/farrellh1\" rel=\"nofollow\">https://github.com/farrellh1</a><p>Email: farrell.hauzan@gmail.com<p>Linkedin: <a href=\"https://www.linkedin.com/in/farrellh/\" rel=\"nofollow\">https://www.linkedin.com/in/farrellh/</a><p>Upwork: <a href=\"https://www.upwork.com/freelancers/~0161da64636535cc02\" rel=\"nofollow\">https://www.upwork.com/freelancers/~0161da64636535cc02</a><p>I\u2019m a full-stack and backend engineer with 5+ years of experience who likes building the product, the services behind it, and the tests that show they work.<p>At Mekari, I worked on a Ruby-to-Go migration and fixed race conditions that cut system escalations by 90%. More recently, I\u2019ve audited 800+ coding-agent benchmark tasks at <em>AfterQuery</em> (YC W25) and built open-source AI evaluation tools, including one that flagged defects in 5 of 25 SWE-bench Verified tasks.<p>I\u2019m also interested in Rust and trading systems. I built an in-memory order book in Rust with a ~104 ns matching hot path, and used Python to research BTC funding-rate signals.<p>Open to full-stack, backend, Rust, AI engineering, and quant engineering or trading-systems roles."},"story_title":{"matchLevel":"none","matchedWords":[],"value":"Ask HN: Who wants to be hired? (October 2026)"}},"_tags":["comment","author_farrellh1","story_49922568"],"author":"farrellh1","comment_text":"Location: Jakarta, Indonesia (UTC+7)<p>Remote: Yes, worldwide<p>Willing to relocate: Yes, with visa sponsorship<p>Technologies: TypeScript&#x2F;JavaScript, Go, Ruby, Python, Rust; \nReact, Next.js, Node.js, Rails, LangGraph; PostgreSQL, MySQL, Redis, Elasticsearch; Docker, AWS; LLM evaluation, multi-agent systems, backtesting<p>R\u00e9sum\u00e9&#x2F;CV: <a href=\"https:&#x2F;&#x2F;farrellh.dev\" rel=\"nofollow\">https:&#x2F;&#x2F;farrellh.dev</a><p>GitHub: <a href=\"https:&#x2F;&#x2F;github.com&#x2F;farrellh1\" rel=\"nofollow\">https:&#x2F;&#x2F;github.com&#x2F;farrellh1</a><p>Email: farrell.hauzan@gmail.com<p>Linkedin: <a href=\"https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;farrellh&#x2F;\" rel=\"nofollow\">https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;farrellh&#x2F;</a><p>Upwork: <a href=\"https:&#x2F;&#x2F;www.upwork.com&#x2F;freelancers&#x2F;~0161da64636535cc02\" rel=\"nofollow\">https:&#x2F;&#x2F;www.upwork.com&#x2F;freelancers&#x2F;~0161da64636535cc02</a><p>I\u2019m a full-stack and backend engineer with 5+ years of experience who likes building the product, the services behind it, and the tests that show they work.<p>At Mekari, I worked on a Ruby-to-Go migration and fixed race conditions that cut system escalations by 90%. More recently, I\u2019ve audited 800+ coding-agent benchmark tasks at AfterQuery (YC W25) and built open-source AI evaluation tools, including one that flagged defects in 5 of 25 SWE-bench Verified tasks.<p>I\u2019m also interested in Rust and trading systems. I built an in-memory order book in Rust with a ~104 ns matching hot path, and used Python to research BTC funding-rate signals.<p>Open to full-stack, backend, Rust, AI engineering, and quant engineering or trading-systems roles.","created_at":"2026-10-06T12:53:17Z","created_at_i":1791291197,"objectID":"49977675","parent_id":49922568,"story_id":49922568,"story_title":"Ask HN: Who wants to be hired? (October 2026)","updated_at":"2026-10-06T16:23:31Z"},{"_highlightResult":{"author":{"matchLevel":"none","matchedWords":[],"value":"throwup238"},"comment_text":{"fullyHighlighted":false,"matchLevel":"full","matchedWords":["afterquery"],"value":"There\u2019s a whole cottage industry of vendors that have provided post training data, private evals, and professional datasets to most (if not all) of the frontier labs. The overlap between OpenAI and Anthropic includes at least Mercor, Surge AI, <em>AfterQuery</em>, Turing, Scale AI, Upwork (for recruiting labelers), Apollo Research, etc."},"story_title":{"matchLevel":"none","matchedWords":[],"value":"A single firm is behind OpenAI, Anthropic, and Meta hacking scandals"},"story_url":{"matchLevel":"none","matchedWords":[],"value":"https://www.effort.news/irregular"}},"_tags":["comment","author_throwup238","story_49704132"],"author":"throwup238","comment_text":"There\u2019s a whole cottage industry of vendors that have provided post training data, private evals, and professional datasets to most (if not all) of the frontier labs. The overlap between OpenAI and Anthropic includes at least Mercor, Surge AI, AfterQuery, Turing, Scale AI, Upwork (for recruiting labelers), Apollo Research, etc.","created_at":"2026-09-15T18:40:24Z","created_at_i":1789497624,"objectID":"49716882","parent_id":49716730,"story_id":49704132,"story_title":"A single firm is behind OpenAI, Anthropic, and Meta hacking scandals","story_url":"https://www.effort.news/irregular","updated_at":"2026-09-16T07:19:11Z"},{"_highlightResult":{"author":{"matchLevel":"none","matchedWords":[],"value":"ansgri"},"comment_text":{"fullyHighlighted":false,"matchLevel":"full","matchedWords":["afterquery"],"value":"Isn't the Online part here about getting results immediately <em>after query</em>, as opposed to overnight batch reports? So if you don't completely overwhelm DuckDB with writes, it still qualifies. The quality you're describing is something like &quot;realtime analytics&quot;, and is a whole another category: Clickhouse doesn't qualify (batching updates, merging etc. \u2014 but it's clearly OLAP), Druid does."},"story_title":{"matchLevel":"none","matchedWords":[],"value":"A sharded DuckDB on 63 nodes runs 1T row aggregation challenge in 5 sec"},"story_url":{"matchLevel":"none","matchedWords":[],"value":"https://gizmodata.com/blog/gizmoedge-one-trillion-row-challenge"}},"_tags":["comment","author_ansgri","story_45694122"],"author":"ansgri","children":[45697833,45697848],"comment_text":"Isn&#x27;t the Online part here about getting results immediately after query, as opposed to overnight batch reports? So if you don&#x27;t completely overwhelm DuckDB with writes, it still qualifies. The quality you&#x27;re describing is something like &quot;realtime analytics&quot;, and is a whole another category: Clickhouse doesn&#x27;t qualify (batching updates, merging etc. \u2014 but it&#x27;s clearly OLAP), Druid does.","created_at":"2025-10-24T18:17:47Z","created_at_i":1761329867,"objectID":"45697514","parent_id":45696700,"story_id":45694122,"story_title":"A sharded DuckDB on 63 nodes runs 1T row aggregation challenge in 5 sec","story_url":"https://gizmodata.com/blog/gizmoedge-one-trillion-row-challenge","updated_at":"2026-03-05T22:54:26Z"},{"_highlightResult":{"author":{"matchLevel":"none","matchedWords":[],"value":"emmelaich"},"comment_text":{"fullyHighlighted":false,"matchLevel":"full","matchedWords":["afterquery"],"value":"That exists as @apenwarr's <em>afterquery</em>: <a href=\"https://apenwarr.ca/log/20121218\" rel=\"nofollow\">https://apenwarr.ca/log/20121218</a><p>As it is the URL string, you can share it easily."},"story_title":{"matchLevel":"none","matchedWords":[],"value":"SQL Injection as a Feature"},"story_url":{"matchLevel":"none","matchedWords":[],"value":"https://idiallo.com/blog/sql-injection-as-a-feature"}},"_tags":["comment","author_emmelaich","story_44638304"],"author":"emmelaich","comment_text":"That exists as @apenwarr&#x27;s afterquery: <a href=\"https:&#x2F;&#x2F;apenwarr.ca&#x2F;log&#x2F;20121218\" rel=\"nofollow\">https:&#x2F;&#x2F;apenwarr.ca&#x2F;log&#x2F;20121218</a><p>As it is the URL string, you can share it easily.","created_at":"2025-07-23T13:13:54Z","created_at_i":1753276434,"objectID":"44658869","parent_id":44658298,"story_id":44638304,"story_title":"SQL Injection as a Feature","story_url":"https://idiallo.com/blog/sql-injection-as-a-feature","updated_at":"2025-07-23T13:19:43Z"},{"_highlightResult":{"author":{"matchLevel":"none","matchedWords":[],"value":"jd3"},"comment_text":{"fullyHighlighted":false,"matchLevel":"full","matchedWords":["afterquery"],"value":"A week before being laid off last month, I solved a decade+ old open problem at our company which first occurred since Django doesn't natively support CTE's, leading to years of technical debt from the ersatz sql/query plans produced by our fragile queries.<p>I ended up manually overloading get_extra_restriction on a custom ForeignKey class (we couldn't use FilteredRelation b/c we were still on django 1.11), which ensured that the JOIN ON ... clause limited the tables being joined to their correct partition/schema while being accessed through a view<p>The view thing is a long story \u2014 it was a legacy PAC codebase from the '90s which used 13+ schemas in a mysql db that was then being synced to our postgres db through Amazon DMS. All of the tables on each view contain identical source_schema/CompanyID columns, hence the<p><pre><code>    '%(remote_alias)s. &quot;source_schema&quot; = %(fk_alias)s. &quot;source_schema&quot; AND '\n    '%(remote_alias)s. &quot;CompanyID&quot; = %(fk_alias)s. &quot;CompanyID&quot;\n</code></pre>\netc. approach<p>before/<em>after query</em> plan in depesz: <a href=\"https://imgur.com/a/HQbNSIL\" rel=\"nofollow\">https://imgur.com/a/HQbNSIL</a>"},"story_title":{"matchLevel":"none","matchedWords":[],"value":"SQL style guide by Simon Holywell"},"story_url":{"matchLevel":"none","matchedWords":[],"value":"https://www.sqlstyle.guide/"}},"_tags":["comment","author_jd3","story_42143528"],"author":"jd3","children":[42145388],"comment_text":"A week before being laid off last month, I solved a decade+ old open problem at our company which first occurred since Django doesn&#x27;t natively support CTE&#x27;s, leading to years of technical debt from the ersatz sql&#x2F;query plans produced by our fragile queries.<p>I ended up manually overloading get_extra_restriction on a custom ForeignKey class (we couldn&#x27;t use FilteredRelation b&#x2F;c we were still on django 1.11), which ensured that the JOIN ON ... clause limited the tables being joined to their correct partition&#x2F;schema while being accessed through a view<p>The view thing is a long story \u2014 it was a legacy PAC codebase from the &#x27;90s which used 13+ schemas in a mysql db that was then being synced to our postgres db through Amazon DMS. All of the tables on each view contain identical source_schema&#x2F;CompanyID columns, hence the<p><pre><code>    &#x27;%(remote_alias)s. &quot;source_schema&quot; = %(fk_alias)s. &quot;source_schema&quot; AND &#x27;\n    &#x27;%(remote_alias)s. &quot;CompanyID&quot; = %(fk_alias)s. &quot;CompanyID&quot;\n</code></pre>\netc. approach<p>before&#x2F;after query plan in depesz: <a href=\"https:&#x2F;&#x2F;imgur.com&#x2F;a&#x2F;HQbNSIL\" rel=\"nofollow\">https:&#x2F;&#x2F;imgur.com&#x2F;a&#x2F;HQbNSIL</a>","created_at":"2024-11-15T07:15:55Z","created_at_i":1731654955,"objectID":"42144593","parent_id":42144521,"story_id":42143528,"story_title":"SQL style guide by Simon Holywell","story_url":"https://www.sqlstyle.guide/","updated_at":"2024-11-15T09:52:35Z"},{"_highlightResult":{"author":{"matchLevel":"none","matchedWords":[],"value":"lobochrome"},"comment_text":{"matchLevel":"none","matchedWords":[],"value":"SYSTEM_PROMPT = f&quot;&quot;&quot;&lt;SYSTEM_CAPABILITY&gt;\n* You are utilising an Ubuntu virtual machine using {platform.machine()} architecture with internet access.\n* You can feel free to install Ubuntu applications with your bash tool. Use curl instead of wget.\n* To open firefox, please just click on the firefox icon.  Note, firefox-esr is what is installed on your system.\n* Using bash tool you can start GUI applications, but you need to set export DISPLAY=:1 and use a subshell. For example &quot;(DISPLAY=:1 xterm &amp;)&quot;. GUI apps run with bash tool will appear within your desktop environment, but they may take some time to appear. Take a screenshot to confirm it did.\n* When using your bash tool with commands that are expected to output very large quantities of text, redirect into a tmp file and use str_replace_editor or `grep -n -B &lt;lines before&gt; -A &lt;lines after&gt; &lt;query&gt; &lt;filename&gt;` to confirm output.\n* When viewing a page it can be helpful to zoom out so that you can see everything on the page.  Either that, or make sure you scroll down to see everything before deciding something isn't available.\n* When using your computer function calls, they take a while to run and send back to you.  Where possible/feasible, try to chain multiple of these calls all into one function calls request.\n* The current date is {datetime.today().strftime('%A, %B %-d, %Y')}.\n&lt;/SYSTEM_CAPABILITY&gt;<p>&lt;IMPORTANT&gt;\n* When using Firefox, if a startup wizard appears, IGNORE IT.  Do not even click &quot;skip this step&quot;.  Instead, click on the address bar where it says &quot;Search or enter address&quot;, and enter the appropriate search term or URL there.\n* If the item you are looking at is a pdf, if after taking a single screenshot of the pdf it seems that you want to read the entire document instead of trying to continue to read the pdf from your screenshots + navigation, determine the URL, use curl to download the pdf, install and use pdftotext to convert it to a text file, and then read that text file directly with your StrReplaceEditTool.\n&lt;/IMPORTANT&gt;&quot;&quot;&quot;"},"story_title":{"matchLevel":"none","matchedWords":[],"value":"Computer use, a new Claude 3.5 Sonnet, and Claude 3.5 Haiku"},"story_url":{"matchLevel":"none","matchedWords":[],"value":"https://www.anthropic.com/news/3-5-models-and-computer-use"}},"_tags":["comment","author_lobochrome","story_41914989"],"author":"lobochrome","children":[41922181,41936398],"comment_text":"SYSTEM_PROMPT = f&quot;&quot;&quot;&lt;SYSTEM_CAPABILITY&gt;\n* You are utilising an Ubuntu virtual machine using {platform.machine()} architecture with internet access.\n* You can feel free to install Ubuntu applications with your bash tool. Use curl instead of wget.\n* To open firefox, please just click on the firefox icon.  Note, firefox-esr is what is installed on your system.\n* Using bash tool you can start GUI applications, but you need to set export DISPLAY=:1 and use a subshell. For example &quot;(DISPLAY=:1 xterm &amp;)&quot;. GUI apps run with bash tool will appear within your desktop environment, but they may take some time to appear. Take a screenshot to confirm it did.\n* When using your bash tool with commands that are expected to output very large quantities of text, redirect into a tmp file and use str_replace_editor or `grep -n -B &lt;lines before&gt; -A &lt;lines after&gt; &lt;query&gt; &lt;filename&gt;` to confirm output.\n* When viewing a page it can be helpful to zoom out so that you can see everything on the page.  Either that, or make sure you scroll down to see everything before deciding something isn&#x27;t available.\n* When using your computer function calls, they take a while to run and send back to you.  Where possible&#x2F;feasible, try to chain multiple of these calls all into one function calls request.\n* The current date is {datetime.today().strftime(&#x27;%A, %B %-d, %Y&#x27;)}.\n&lt;&#x2F;SYSTEM_CAPABILITY&gt;<p>&lt;IMPORTANT&gt;\n* When using Firefox, if a startup wizard appears, IGNORE IT.  Do not even click &quot;skip this step&quot;.  Instead, click on the address bar where it says &quot;Search or enter address&quot;, and enter the appropriate search term or URL there.\n* If the item you are looking at is a pdf, if after taking a single screenshot of the pdf it seems that you want to read the entire document instead of trying to continue to read the pdf from your screenshots + navigation, determine the URL, use curl to download the pdf, install and use pdftotext to convert it to a text file, and then read that text file directly with your StrReplaceEditTool.\n&lt;&#x2F;IMPORTANT&gt;&quot;&quot;&quot;","created_at":"2024-10-23T04:43:48Z","created_at_i":1729658628,"objectID":"41921898","parent_id":41921690,"story_id":41914989,"story_title":"Computer use, a new Claude 3.5 Sonnet, and Claude 3.5 Haiku","story_url":"https://www.anthropic.com/news/3-5-models-and-computer-use","updated_at":"2024-10-24T19:02:54Z"},{"_highlightResult":{"author":{"matchLevel":"none","matchedWords":[],"value":"Jasper_"},"comment_text":{"fullyHighlighted":false,"matchLevel":"full","matchedWords":["afterquery"],"value":"The a=b&amp;c=d syntax is part of application/x-www-url-formencoded which was a Mosaic invention, and came <em>after query</em> strings. [0] [1]<p>[0] <a href=\"http://1997.webhistory.org/www.lists/www-talk.1993q3/0812.html\" rel=\"nofollow noreferrer\">http://1997.webhistory.org/www.lists/www-talk.1993q3/0812.ht...</a><p>[1] <a href=\"https://web.archive.org/web/19961220100435/http://www.ncsa.uiuc.edu/SDG/Software/Mosaic/Docs/fill-out-forms/overview.html\" rel=\"nofollow noreferrer\">https://web.archive.org/web/19961220100435/http://www.ncsa.u...</a>"},"story_title":{"matchLevel":"none","matchedWords":[],"value":"URL Explained \u2013 The Fundamentals"},"story_url":{"matchLevel":"none","matchedWords":[],"value":"https://ittavern.com/url-explained-the-fundamentals/"}},"_tags":["comment","author_Jasper_","story_38249404"],"author":"Jasper_","comment_text":"The a=b&amp;c=d syntax is part of application&#x2F;x-www-url-formencoded which was a Mosaic invention, and came after query strings. [0] [1]<p>[0] <a href=\"http:&#x2F;&#x2F;1997.webhistory.org&#x2F;www.lists&#x2F;www-talk.1993q3&#x2F;0812.html\" rel=\"nofollow noreferrer\">http:&#x2F;&#x2F;1997.webhistory.org&#x2F;www.lists&#x2F;www-talk.1993q3&#x2F;0812.ht...</a><p>[1] <a href=\"https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;19961220100435&#x2F;http:&#x2F;&#x2F;www.ncsa.uiuc.edu&#x2F;SDG&#x2F;Software&#x2F;Mosaic&#x2F;Docs&#x2F;fill-out-forms&#x2F;overview.html\" rel=\"nofollow noreferrer\">https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;19961220100435&#x2F;http:&#x2F;&#x2F;www.ncsa.u...</a>","created_at":"2023-11-14T07:30:32Z","created_at_i":1699947032,"objectID":"38260167","parent_id":38256376,"story_id":38249404,"story_title":"URL Explained \u2013 The Fundamentals","story_url":"https://ittavern.com/url-explained-the-fundamentals/","updated_at":"2024-09-20T15:39:30Z"},{"_highlightResult":{"author":{"matchLevel":"none","matchedWords":[],"value":"6510"},"comment_text":{"fullyHighlighted":false,"matchLevel":"full","matchedWords":["afterquery"],"value":"I still weekly make the mistake to try to find something that I know to exist. Sometimes I know there are hundreds of pages on the topic. I type query <em>after query</em>, again and again, nothing shows up. It's like in the 90's, I tell stories about.. I forget his name and the place, when it happened but it was something like this and that. pfft!<p>edit: I just attempted to look up what kind of taxes on has to pay if one receives donations. I cant carve out a query that gives me anything other than tax deductible donations. The &quot;receiving&quot; part is completely ignored."},"story_title":{"matchLevel":"none","matchedWords":[],"value":"FB feed is 98% suggested pages and barely any friends' posts"},"story_url":{"matchLevel":"none","matchedWords":[],"value":"https://old.reddit.com/r/facebook/comments/tvqddc/fb_feed_is_98_suggested_pages_and_barely_any/"}},"_tags":["comment","author_6510","story_32826437"],"author":"6510","children":[32851230],"comment_text":"I still weekly make the mistake to try to find something that I know to exist. Sometimes I know there are hundreds of pages on the topic. I type query after query, again and again, nothing shows up. It&#x27;s like in the 90&#x27;s, I tell stories about.. I forget his name and the place, when it happened but it was something like this and that. pfft!<p>edit: I just attempted to look up what kind of taxes on has to pay if one receives donations. I cant carve out a query that gives me anything other than tax deductible donations. The &quot;receiving&quot; part is completely ignored.","created_at":"2022-09-13T22:20:52Z","created_at_i":1663107652,"objectID":"32830910","parent_id":32828555,"story_id":32826437,"story_title":"FB feed is 98% suggested pages and barely any friends' posts","story_url":"https://old.reddit.com/r/facebook/comments/tvqddc/fb_feed_is_98_suggested_pages_and_barely_any/","updated_at":"2024-09-20T12:00:37Z"},{"_highlightResult":{"author":{"matchLevel":"none","matchedWords":[],"value":"agent281"},"comment_text":{"fullyHighlighted":false,"matchLevel":"full","matchedWords":["afterquery"],"value":"Before I start, let me say that I'm on mobile and I don't know how to post code on this site. I'm assuming backticks work.<p>---<p>One benefit is that functions are more reusable. Functions with more arguments can be partially applied and used where applicable.<p>For instance, if you wanted to increment the values in a list you might do something like this in python:<p><pre><code>  map(lambda x: x + 1, [1,2,3])\n</code></pre>\nBut in an ML like language you can do something like:<p><pre><code>  map((+ 1), [1,2,3])\n</code></pre>\nBecause plus is actually a function that takes two arguments and can be curried down to one argument.<p>Additionally, you can think of currying as a form of dependency injection.<p>For example, if you wanted to inject a database client and a logger before running a query you might do something like this:<p><pre><code>  def queryer(db, logger):\n    def _q(query):\n      logger.info(&quot;before query&quot;)\n      results = db.fetch(query)\n      logger.info(&quot;<em>after query</em>&quot;)\n      return results\n\n    return _q\n\n  rows = queryer(db, logger)(query)\n\n</code></pre>\nYou could write it a bit more simply in this hypothetical ML like language:<p><pre><code>  queryer db logger query =\n      logger.info(&quot;before query&quot;)\n      results = db.fetch(query)\n      logger.info(&quot;<em>after query</em>&quot;)\n      results\n</code></pre>\nMLs don't require parens/commas for function calls, but you can use parens to force a particular execution order. The lines below have the same result, but some produce and execute intermediate curried functions<p><pre><code>  rows = queryer db logger query\n  rows = (queryer db) logger query\n  rows = ((queryer db) logger) query\n</code></pre>\nIt's a bit contrived, but you have the flexibility to provide some arguments based on the call site rather than the definition site. I.e., the first example was broken up into 2 function calls at the definition site, but the second example could have 1, 2, or 3 function calls.<p>---<p>I hope this makes sense and I wish I could preview my comment to see if it was formatted reasonably!"},"story_title":{"matchLevel":"none","matchedWords":[],"value":"OCaml Programming: Correct and Efficient and Beautiful"},"story_url":{"matchLevel":"none","matchedWords":[],"value":"https://cs3110.github.io/textbook/cover.html"}},"_tags":["comment","author_agent281","story_31848178"],"author":"agent281","comment_text":"Before I start, let me say that I&#x27;m on mobile and I don&#x27;t know how to post code on this site. I&#x27;m assuming backticks work.<p>---<p>One benefit is that functions are more reusable. Functions with more arguments can be partially applied and used where applicable.<p>For instance, if you wanted to increment the values in a list you might do something like this in python:<p><pre><code>  map(lambda x: x + 1, [1,2,3])\n</code></pre>\nBut in an ML like language you can do something like:<p><pre><code>  map((+ 1), [1,2,3])\n</code></pre>\nBecause plus is actually a function that takes two arguments and can be curried down to one argument.<p>Additionally, you can think of currying as a form of dependency injection.<p>For example, if you wanted to inject a database client and a logger before running a query you might do something like this:<p><pre><code>  def queryer(db, logger):\n    def _q(query):\n      logger.info(&quot;before query&quot;)\n      results = db.fetch(query)\n      logger.info(&quot;after query&quot;)\n      return results\n\n    return _q\n\n  rows = queryer(db, logger)(query)\n\n</code></pre>\nYou could write it a bit more simply in this hypothetical ML like language:<p><pre><code>  queryer db logger query =\n      logger.info(&quot;before query&quot;)\n      results = db.fetch(query)\n      logger.info(&quot;after query&quot;)\n      results\n</code></pre>\nMLs don&#x27;t require parens&#x2F;commas for function calls, but you can use parens to force a particular execution order. The lines below have the same result, but some produce and execute intermediate curried functions<p><pre><code>  rows = queryer db logger query\n  rows = (queryer db) logger query\n  rows = ((queryer db) logger) query\n</code></pre>\nIt&#x27;s a bit contrived, but you have the flexibility to provide some arguments based on the call site rather than the definition site. I.e., the first example was broken up into 2 function calls at the definition site, but the second example could have 1, 2, or 3 function calls.<p>---<p>I hope this makes sense and I wish I could preview my comment to see if it was formatted reasonably!","created_at":"2022-06-25T16:15:31Z","created_at_i":1656173731,"objectID":"31876444","parent_id":31868084,"story_id":31848178,"story_title":"OCaml Programming: Correct and Efficient and Beautiful","story_url":"https://cs3110.github.io/textbook/cover.html","updated_at":"2024-09-20T11:29:01Z"},{"_highlightResult":{"author":{"matchLevel":"none","matchedWords":[],"value":"karmakaze"},"comment_text":{"fullyHighlighted":false,"matchLevel":"full","matchedWords":["afterquery"],"value":"I remember, I do have a recent one. An application/service was ported from PostgreSQL to MySQL but there was a particular set of queries that used to run in a 5-10 minutes that wouldn't finish in 6h+. It was due for release so had a set Friday deadline giving us almost a week. The queries were large and complicated having been evolved over the course of app development specific to PostgreSQL. Also complicated by the queries being dynamically built at runtime with various in/out optional parts. If you look at the main slow core, and by comparing query plans on pg vs mysql, we could see that pg did more 'query plan normalization' (or rewriting in a way). After that we rewrote bits and bits of the query adding indexes, and partial subqueries for reuse, de-correlating subqueries, moving functions from SQL to code before/<em>after query</em>, force index hints, etc. By Friday we got it down to under a minute. One tip was recognizing that one of the columns in the tables was a tenant key so its cardinality was useless if already using a higher cardinality index. DBs should really have a representation for this. Writing SQL for MySQL is like writing C vs writing Prolog for PostgreSQL.<p>Another old one was getting a large OS/2 program to run in DOS 640 KB with overlay segments that swapped out. The trick being that you want to minimize transitions between overlay segments. Parsed a call tree of the entire program and assigned overlay numbers based on some large chunks of subtrees with the most common leaf calls being in segment 99 that always lived within the 640KB. It ran fast enough and shipped without revising the shrink wrap dates."},"story_title":{"matchLevel":"none","matchedWords":[],"value":"Ask HN: What's your 10x developer story?"}},"_tags":["comment","author_karmakaze","story_31506355"],"author":"karmakaze","comment_text":"I remember, I do have a recent one. An application&#x2F;service was ported from PostgreSQL to MySQL but there was a particular set of queries that used to run in a 5-10 minutes that wouldn&#x27;t finish in 6h+. It was due for release so had a set Friday deadline giving us almost a week. The queries were large and complicated having been evolved over the course of app development specific to PostgreSQL. Also complicated by the queries being dynamically built at runtime with various in&#x2F;out optional parts. If you look at the main slow core, and by comparing query plans on pg vs mysql, we could see that pg did more &#x27;query plan normalization&#x27; (or rewriting in a way). After that we rewrote bits and bits of the query adding indexes, and partial subqueries for reuse, de-correlating subqueries, moving functions from SQL to code before&#x2F;after query, force index hints, etc. By Friday we got it down to under a minute. One tip was recognizing that one of the columns in the tables was a tenant key so its cardinality was useless if already using a higher cardinality index. DBs should really have a representation for this. Writing SQL for MySQL is like writing C vs writing Prolog for PostgreSQL.<p>Another old one was getting a large OS&#x2F;2 program to run in DOS 640 KB with overlay segments that swapped out. The trick being that you want to minimize transitions between overlay segments. Parsed a call tree of the entire program and assigned overlay numbers based on some large chunks of subtrees with the most common leaf calls being in segment 99 that always lived within the 640KB. It ran fast enough and shipped without revising the shrink wrap dates.","created_at":"2022-05-25T22:33:09Z","created_at_i":1653517989,"objectID":"31511612","parent_id":31506355,"story_id":31506355,"story_title":"Ask HN: What's your 10x developer story?","updated_at":"2024-09-20T11:11:40Z"},{"_highlightResult":{"author":{"matchLevel":"none","matchedWords":[],"value":"uhoh-itsmaciek"},"comment_text":{"fullyHighlighted":false,"matchLevel":"full","matchedWords":["afterquery"],"value":"Due to some Postgres limitations, a query can run even after the connection drops (the backend process only checks if there's still a client to send results to <em>after query</em> completion). I think I saw some work being done on this in 14 or the upcoming 15 (i.e., to re-check periodically <i>during</i> query processing), but a lot of Postgres versions are still affected. I worked on the Heroku Data team and we regularly saw queries running for days. I think starting with an aggressive timeout to fail fast where you can't afford a slow query anyway, and then make exceptions where it makes sense, is easier to work with than tracking down problem cases and putting in limits after they cause issues."},"story_title":{"matchLevel":"none","matchedWords":[],"value":"Tips for a Healthier Postgres Database"},"story_url":{"matchLevel":"none","matchedWords":[],"value":"https://blog.crunchydata.com/blog/five-tips-for-a-healthier-postgres-database-in-the-new-year"}},"_tags":["comment","author_uhoh-itsmaciek","story_29858083"],"author":"uhoh-itsmaciek","comment_text":"Due to some Postgres limitations, a query can run even after the connection drops (the backend process only checks if there&#x27;s still a client to send results to after query completion). I think I saw some work being done on this in 14 or the upcoming 15 (i.e., to re-check periodically <i>during</i> query processing), but a lot of Postgres versions are still affected. I worked on the Heroku Data team and we regularly saw queries running for days. I think starting with an aggressive timeout to fail fast where you can&#x27;t afford a slow query anyway, and then make exceptions where it makes sense, is easier to work with than tracking down problem cases and putting in limits after they cause issues.","created_at":"2022-01-10T20:59:55Z","created_at_i":1641848395,"objectID":"29882352","parent_id":29865040,"story_id":29858083,"story_title":"Tips for a Healthier Postgres Database","story_url":"https://blog.crunchydata.com/blog/five-tips-for-a-healthier-postgres-database-in-the-new-year","updated_at":"2024-09-20T10:16:44Z"},{"_highlightResult":{"author":{"matchLevel":"none","matchedWords":[],"value":"enjo"},"comment_text":{"fullyHighlighted":false,"matchLevel":"full","matchedWords":["afterquery"],"value":"It's not just for newbies. I'm competent with SQL, but that doesn't mean I enjoy writing query <em>after query</em>. We use Django and utilize the ORM... we jump down into SQL in the (rare) case that we really need too.<p>I'm sure at higher scale (we're mid-level at this point) that we might be hand tuning more and more, but that hasn't happened yet."},"story_title":{"matchLevel":"none","matchedWords":[],"value":"ORM is an anti-pattern"},"story_url":{"matchLevel":"none","matchedWords":[],"value":"http://seldo.com/weblog/2011/06/15/orm_is_an_antipattern"}},"_tags":["comment","author_enjo","story_2657745"],"author":"enjo","comment_text":"It's not just for newbies. I'm competent with SQL, but that doesn't mean I enjoy writing query after query. We use Django and utilize the ORM... we jump down into SQL in the (rare) case that we really need too.<p>I'm sure at higher scale (we're mid-level at this point) that we might be hand tuning more and more, but that hasn't happened yet.","created_at":"2011-06-15T17:29:16Z","created_at_i":1308158956,"objectID":"2658107","parent_id":2657950,"story_id":2657745,"story_title":"ORM is an anti-pattern","story_url":"http://seldo.com/weblog/2011/06/15/orm_is_an_antipattern","updated_at":"2024-09-19T17:46:01Z"},{"_highlightResult":{"author":{"matchLevel":"none","matchedWords":[],"value":"rdtsc"},"comment_text":{"fullyHighlighted":false,"matchLevel":"full","matchedWords":["afterquery"],"value":"Here are some:<p>* Added _replicator database to manage replications.<p>It used to be that if a continuous replication was launched but the server was re-started that replication task was lost. Now it will continue where it left off.<p>* Added support for HTTP range requests for attachments.<p>Just looking at the unit-test for this commit, you can apparently specify a range of bytes out of an attachment and fetch only that.<p><pre><code>    var xhr = CouchDB.request(\"GET\", \"/test_suite_db/bin_doc/foo.txt\", {\n \theaders: {\"Range\": \"bytes=10-15\"}\n \t}); \n</code></pre>\n* Added stale=update_<em>after query</em> option that triggers a view update after returning a stale=ok response.<p>Before, if stale=ok was passed to a view then you'd just get back stale view data and (I am guessing) a view update wasn't triggered. Normally a view update is triggerred the frist time the view is accessed after documents have been updated. However that could take a while for the views to regenerate. Now with stale=update, stale data is returned but an view update is _also_ triggerred in the background.<p>* Added configuration option for TCP_NODELAY aka \u201cNagle\u201d.<p>Should help for situations where you'd want to trade some throughput for latency. Your packets will be sent out sooner, they will be smaller, but there will probably be lots more of them.  See here for more :<p><pre><code>  http://en.wikipedia.org/wiki/Nagle%27s_algorithm</code></pre>"},"story_title":{"matchLevel":"none","matchedWords":[],"value":"CouchDB 1.1.0"},"story_url":{"matchLevel":"none","matchedWords":[],"value":"http://couchdb.apache.org/downloads.html"}},"_tags":["comment","author_rdtsc","story_2624685"],"author":"rdtsc","comment_text":"Here are some:<p>* Added _replicator database to manage replications.<p>It used to be that if a continuous replication was launched but the server was re-started that replication task was lost. Now it will continue where it left off.<p>* Added support for HTTP range requests for attachments.<p>Just looking at the unit-test for this commit, you can apparently specify a range of bytes out of an attachment and fetch only that.<p><pre><code>    var xhr = CouchDB.request(\"GET\", \"/test_suite_db/bin_doc/foo.txt\", {\n \theaders: {\"Range\": \"bytes=10-15\"}\n \t}); \n</code></pre>\n* Added stale=update_after query option that triggers a view update after returning a stale=ok response.<p>Before, if stale=ok was passed to a view then you'd just get back stale view data and (I am guessing) a view update wasn't triggered. Normally a view update is triggerred the frist time the view is accessed after documents have been updated. However that could take a while for the views to regenerate. Now with stale=update, stale data is returned but an view update is _also_ triggerred in the background.<p>* Added configuration option for TCP_NODELAY aka \u201cNagle\u201d.<p>Should help for situations where you'd want to trade some throughput for latency. Your packets will be sent out sooner, they will be smaller, but there will probably be lots more of them.  See here for more :<p><pre><code>  http://en.wikipedia.org/wiki/Nagle%27s_algorithm</code></pre>","created_at":"2011-06-06T15:02:30Z","created_at_i":1307372550,"objectID":"2624927","parent_id":2624811,"story_id":2624685,"story_title":"CouchDB 1.1.0","story_url":"http://couchdb.apache.org/downloads.html","updated_at":"2024-09-19T17:42:45Z"},{"_highlightResult":{"author":{"matchLevel":"none","matchedWords":[],"value":"cosmie"},"comment_text":{"fullyHighlighted":false,"matchLevel":"full","matchedWords":["afterquery"],"value":"Join performance is a bit of a hairy topic.<p>If you're pulling data from an external source that supports query folding[1] such as a database, it'll try to push those joins to the original source.<p>If you're pulling in data from a source that doesn't (or the join occurs <em>after query</em> folding is no longer possible), there are a host of performance considerations/optimizations.<p>By default PowerQuery knows nothing about your source data and makes no assumptions. If you're joining data using the GUI, the generated code will likely use the NestedJoin[2] function. A single &quot;step&quot; in the processing will have its ram capped at 256MB[3], so depending on the size of the data you're joining and absent of any data processing steps that would give it guarantees about your data, you may or may not be paging massive amounts of data to disk as it loops through the entire dataset you're joining for each row that is being joined.<p>That said, PowerQuery has 6-7 join algorithms available, and a variety of techniques that can be used to optimize the processing. For example, if you add a primary key to the table (via Table.AddKey or Table.Distinct or Table.Group), it can short-circuit the data processing the moment it finds a match. This[4] article series is really helpful for optimizing joins in particular and the link-outs and tidbits scattered within the series are fantastic for getting a better understanding of PowerQuery's inner workings and performance considerations.<p>[1] <a href=\"https://docs.microsoft.com/en-us/power-query/power-query-folding\" rel=\"nofollow\">https://docs.microsoft.com/en-us/power-query/power-query-fol...</a><p>[2] <a href=\"https://docs.microsoft.com/en-us/powerquery-m/table-nestedjoin\" rel=\"nofollow\">https://docs.microsoft.com/en-us/powerquery-m/table-nestedjo...</a><p>[3] Mentioned halfway down this article: <a href=\"https://blog.crossjoin.co.uk/2019/04/21/power-bi-dataflow-container-size/\" rel=\"nofollow\">https://blog.crossjoin.co.uk/2019/04/21/power-bi-dataflow-co...</a><p>[4] <a href=\"https://blog.crossjoin.co.uk/2020/05/31/optimising-the-performance-of-power-query-merges-in-power-bi-part-1/\" rel=\"nofollow\">https://blog.crossjoin.co.uk/2020/05/31/optimising-the-perfo...</a>"},"story_title":{"matchLevel":"none","matchedWords":[],"value":"Excel warriors who save governments and companies from spreadsheet errors"},"story_url":{"matchLevel":"none","matchedWords":[],"value":"https://www.wired.co.uk/article/spreadsheet-excel-errors"}},"_tags":["comment","author_cosmie","story_24791017"],"author":"cosmie","comment_text":"Join performance is a bit of a hairy topic.<p>If you&#x27;re pulling data from an external source that supports query folding[1] such as a database, it&#x27;ll try to push those joins to the original source.<p>If you&#x27;re pulling in data from a source that doesn&#x27;t (or the join occurs after query folding is no longer possible), there are a host of performance considerations&#x2F;optimizations.<p>By default PowerQuery knows nothing about your source data and makes no assumptions. If you&#x27;re joining data using the GUI, the generated code will likely use the NestedJoin[2] function. A single &quot;step&quot; in the processing will have its ram capped at 256MB[3], so depending on the size of the data you&#x27;re joining and absent of any data processing steps that would give it guarantees about your data, you may or may not be paging massive amounts of data to disk as it loops through the entire dataset you&#x27;re joining for each row that is being joined.<p>That said, PowerQuery has 6-7 join algorithms available, and a variety of techniques that can be used to optimize the processing. For example, if you add a primary key to the table (via Table.AddKey or Table.Distinct or Table.Group), it can short-circuit the data processing the moment it finds a match. This[4] article series is really helpful for optimizing joins in particular and the link-outs and tidbits scattered within the series are fantastic for getting a better understanding of PowerQuery&#x27;s inner workings and performance considerations.<p>[1] <a href=\"https:&#x2F;&#x2F;docs.microsoft.com&#x2F;en-us&#x2F;power-query&#x2F;power-query-folding\" rel=\"nofollow\">https:&#x2F;&#x2F;docs.microsoft.com&#x2F;en-us&#x2F;power-query&#x2F;power-query-fol...</a><p>[2] <a href=\"https:&#x2F;&#x2F;docs.microsoft.com&#x2F;en-us&#x2F;powerquery-m&#x2F;table-nestedjoin\" rel=\"nofollow\">https:&#x2F;&#x2F;docs.microsoft.com&#x2F;en-us&#x2F;powerquery-m&#x2F;table-nestedjo...</a><p>[3] Mentioned halfway down this article: <a href=\"https:&#x2F;&#x2F;blog.crossjoin.co.uk&#x2F;2019&#x2F;04&#x2F;21&#x2F;power-bi-dataflow-container-size&#x2F;\" rel=\"nofollow\">https:&#x2F;&#x2F;blog.crossjoin.co.uk&#x2F;2019&#x2F;04&#x2F;21&#x2F;power-bi-dataflow-co...</a><p>[4] <a href=\"https:&#x2F;&#x2F;blog.crossjoin.co.uk&#x2F;2020&#x2F;05&#x2F;31&#x2F;optimising-the-performance-of-power-query-merges-in-power-bi-part-1&#x2F;\" rel=\"nofollow\">https:&#x2F;&#x2F;blog.crossjoin.co.uk&#x2F;2020&#x2F;05&#x2F;31&#x2F;optimising-the-perfo...</a>","created_at":"2020-10-16T23:20:09Z","created_at_i":1602890409,"objectID":"24805943","parent_id":24805621,"story_id":24791017,"story_title":"Excel warriors who save governments and companies from spreadsheet errors","story_url":"https://www.wired.co.uk/article/spreadsheet-excel-errors","updated_at":"2024-09-20T07:04:22Z"}],"hitsPerPage":20,"nbHits":26,"nbPages":2,"page":0,"params":"query=afterquery&advancedSyntax=true&analyticsTags=backend","processingTimeMS":24,"processingTimingsMS":{"_request":{"roundTrip":17},"afterFetch":{"format":{"highlighting":3,"total":3},"merge":{"mergeLoop":{"prepareNextHit":9,"total":9},"total":9},"total":9},"fetch":{"query":9,"scanning":4,"total":14},"total":25},"query":"afterquery","serverTimeMS":29}
