<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>SuMingXuan (苏铭轩)</title>
    <link>https://ruby-china.org/SuMingXuan</link>
    <description>摸鲸校尉</description>
    <language>en-us</language>
    <item>
      <title>浅析 PostgreSQL + zhparser 进行中文搜索的分词与排序优化</title>
      <description>&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;之前在做 &lt;a href="https://resources.gitlab.cn/" rel="nofollow" target="_blank" title=""&gt;gitlab resource center&lt;/a&gt; 搜索功能时，初版上线的搜索结果未能令人满意。因此便开始着手对分词和排序进行了改进。&lt;/p&gt;

&lt;p&gt;在第一版搜索功能上线后，当输入关键字&lt;code&gt;安全高效&lt;/code&gt;和&lt;code&gt;安全&lt;/code&gt;时，系统能够正确返回相关文章。然而，在搜索&lt;code&gt;高效&lt;/code&gt;关键字时，却发现返回的文章为空。期望的功能是，只要文章标题、内容或描述中包含关键字&lt;code&gt;高效&lt;/code&gt;，就能够返回相关结果。&lt;/p&gt;
&lt;h2 id="分词"&gt;分词&lt;/h2&gt;
&lt;p&gt;首先我们看看怎么在 PostgreSQL 中启用 &lt;code&gt;zhparser&lt;/code&gt; 插件的：&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;zhparser&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;SEARCH&lt;/span&gt; &lt;span class="n"&gt;CONFIGURATION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;chinese_zh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;SEARCH&lt;/span&gt; &lt;span class="n"&gt;CONFIGURATION&lt;/span&gt; &lt;span class="n"&gt;chinese_zh&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PARSER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zhparser&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;SEARCH&lt;/span&gt; &lt;span class="n"&gt;CONFIGURATION&lt;/span&gt; &lt;span class="n"&gt;chinese_zh&lt;/span&gt; &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="n"&gt;MAPPING&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;simple&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里的 a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z 均对应了一种词性。&lt;/p&gt;

&lt;p&gt;下面是词性的关系映射表，先列举出来，用于我们后面分析。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;97&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"adjective,        形容词"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;98&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"differentiation,  区别词"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"conjunction,      连词"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"adverb,           副词"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"exclamation,      感叹词"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;102&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"position,         方位词"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;103&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"root,             词根"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;104&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"head,             前连接成分"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;105&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"idiom,            成语"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;106&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"abbreviation,     简称"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;107&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"tail,             后连接成分"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;108&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"tmp,              习用语"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;109&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"numeral,          数词"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;110&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"noun,             名词"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;111&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"onomatopoeia,     拟声词"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;112&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"prepositional,    介词"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;113&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"quantity,         量词"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;114&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"pronoun,          代词"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;115&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"space,            处所词"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;116&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"time,             时语素"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;117&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"auxiliary,        助词"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;118&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"verb,             动词"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;119&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"punctuation,      标点符号"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"unknown,          未知词"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;121&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"modal,            语气词"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;122&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"status,           状态词"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们直接通过 zhparser 分词策略分词之后的看看他的返回结果&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;ts_parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'zhparser'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'这种将安全高效整合进研发和运维流程中的安全构建方式'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

 &lt;span class="n"&gt;tokid&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;  &lt;span class="n"&gt;token&lt;/span&gt;
&lt;span class="c1"&gt;-------+----------&lt;/span&gt;
   &lt;span class="mi"&gt;114&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;这种&lt;/span&gt;
   &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;将&lt;/span&gt;
   &lt;span class="mi"&gt;110&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;安全高效&lt;/span&gt;
   &lt;span class="mi"&gt;118&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;整&lt;/span&gt;
   &lt;span class="mi"&gt;110&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;合进&lt;/span&gt;
   &lt;span class="mi"&gt;106&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;研发&lt;/span&gt;
    &lt;span class="mi"&gt;99&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;和&lt;/span&gt;
   &lt;span class="mi"&gt;118&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;运&lt;/span&gt;
   &lt;span class="mi"&gt;113&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;维&lt;/span&gt;
   &lt;span class="mi"&gt;110&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;流程&lt;/span&gt;
   &lt;span class="mi"&gt;102&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;中&lt;/span&gt;
   &lt;span class="mi"&gt;117&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;的&lt;/span&gt;
    &lt;span class="mi"&gt;97&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;安全&lt;/span&gt;
   &lt;span class="mi"&gt;118&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;构建&lt;/span&gt;
   &lt;span class="mi"&gt;110&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;方式&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- 对应的词性可以在上面的关系映射表里面看&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时 zhparser 会拆分出 &lt;code&gt;安全高效&lt;/code&gt; 和 &lt;code&gt;安全&lt;/code&gt; 这两个词，并没有拆分出我们所需要的 &lt;code&gt;高效&lt;/code&gt; 关键词。&lt;/p&gt;

&lt;p&gt;zhparser 有以下配置，且所有配置默认值均为 false。&lt;/p&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;zhparser&lt;/span&gt;.&lt;span class="n"&gt;punctuation_ignore&lt;/span&gt; = &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="c"&gt;#忽略所有的标点等特殊符号: 
&lt;/span&gt;&lt;span class="n"&gt;zhparser&lt;/span&gt;.&lt;span class="n"&gt;seg_with_duality&lt;/span&gt; = &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="c"&gt;#闲散文字自动以二字分词法聚合: 
&lt;/span&gt;&lt;span class="n"&gt;zhparser&lt;/span&gt;.&lt;span class="n"&gt;dict_in_memory&lt;/span&gt; = &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="c"&gt;#将词典全部加载到内存里: 
&lt;/span&gt;&lt;span class="n"&gt;zhparser&lt;/span&gt;.&lt;span class="n"&gt;multi_short&lt;/span&gt; = &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="c"&gt;#短词复合: 
&lt;/span&gt;&lt;span class="n"&gt;zhparser&lt;/span&gt;.&lt;span class="n"&gt;multi_duality&lt;/span&gt; = &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="c"&gt;#散字二元复合: 
&lt;/span&gt;&lt;span class="n"&gt;zhparser&lt;/span&gt;.&lt;span class="n"&gt;multi_zmain&lt;/span&gt; = &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="c"&gt;#重要单字复合: 
&lt;/span&gt;&lt;span class="n"&gt;zhparser&lt;/span&gt;.&lt;span class="n"&gt;multi_zall&lt;/span&gt; = &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="c"&gt;#全部单字复合: 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为 zhparser 插件是一个基于 &lt;a href="https://github.com/hightman/scws" rel="nofollow" target="_blank" title=""&gt;SCWS&lt;/a&gt; 能力开发的 PG 中文分词插件。所以我们可以去 &lt;a href="http://www.xunsearch.com/scws/demo/v48.php" rel="nofollow" target="_blank" title=""&gt;SCWS 在线测试平台&lt;/a&gt; 根据需要做一些调整。最终我们决定将&lt;code&gt;短词复合&lt;/code&gt;配置打开。有以下两种方式去配置（具体怎么应用看对应的云服务商怎么方便处理。）：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;修改 &lt;code&gt;postgresql.conf&lt;/code&gt; 文件配置&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;将 &lt;code&gt;zhparser.multi_short = true&lt;/code&gt; 添加到 &lt;code&gt;postgresql.conf&lt;/code&gt; 文件中，然后进入数据库执行 &lt;code&gt;SELECT pg_reload_conf();&lt;/code&gt; 使 PostgreSQL 重新加载配置文件。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;通过 sql 命令配置&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;set_config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'zhparser.multi_short'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'true'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;SYSTEM&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;zhparser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;multi_short&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;pg_reload_conf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;需要注意：执行 sql 必须是原生的 superuser 权限，并且执行 sql 的时候不能在事务中运行&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;将以上配置完毕之后再来看看 zhparser 分词结果是什么&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;ts_parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'zhparser'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'这种将安全高效整合进研发和运维流程中的安全构建方式'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

 &lt;span class="n"&gt;tokid&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;  &lt;span class="n"&gt;token&lt;/span&gt;
&lt;span class="c1"&gt;-------+----------&lt;/span&gt;
   &lt;span class="mi"&gt;114&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;这种&lt;/span&gt;
   &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;将&lt;/span&gt;
   &lt;span class="mi"&gt;110&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;安全高效&lt;/span&gt;
    &lt;span class="mi"&gt;97&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;安全&lt;/span&gt;
   &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;高效&lt;/span&gt;
   &lt;span class="mi"&gt;118&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;整&lt;/span&gt;
   &lt;span class="mi"&gt;110&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;合进&lt;/span&gt;
   &lt;span class="mi"&gt;106&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;研发&lt;/span&gt;
    &lt;span class="mi"&gt;99&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;和&lt;/span&gt;
   &lt;span class="mi"&gt;118&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;运&lt;/span&gt;
   &lt;span class="mi"&gt;113&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;维&lt;/span&gt;
   &lt;span class="mi"&gt;110&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;流程&lt;/span&gt;
   &lt;span class="mi"&gt;102&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;中&lt;/span&gt;
   &lt;span class="mi"&gt;117&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;的&lt;/span&gt;
    &lt;span class="mi"&gt;97&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;安全&lt;/span&gt;
   &lt;span class="mi"&gt;118&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;构建&lt;/span&gt;
   &lt;span class="mi"&gt;110&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;方式&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt; &lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- 对应的词性可以在上面的关系映射表里面看&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时&lt;code&gt;高效&lt;/code&gt;关键词已经被拆分出来了，并且它是&lt;code&gt;副词&lt;/code&gt;词性，接下来调整下 &lt;code&gt;chinese_zh&lt;/code&gt; 的策略，只保留我们需要的词性&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- 删除分词策略：&lt;/span&gt;

&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;SEARCH&lt;/span&gt; &lt;span class="n"&gt;CONFIGURATION&lt;/span&gt; &lt;span class="n"&gt;chinese_zh&lt;/span&gt; &lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="n"&gt;MAPPING&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;exists&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- 添加分词策略：&lt;/span&gt;
&lt;span class="c1"&gt;-- 添加名词（n）、动词（v）、形容词（a）、成语（i）、叹词（e）、习用语（l）和副词（d）七种分词策略：&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;SEARCH&lt;/span&gt; &lt;span class="n"&gt;CONFIGURATION&lt;/span&gt; &lt;span class="n"&gt;chinese_zh&lt;/span&gt; &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="n"&gt;MAPPING&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;simple&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后观察 &lt;code&gt;chinese_zh&lt;/code&gt; 的分词结果&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;to_tsvector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chinese_zh'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="s1"&gt;'这种将安全高效整合进研发和运维流程中的安全构建方式'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                                &lt;span class="n"&gt;to_tsvector&lt;/span&gt;
&lt;span class="c1"&gt;---------------------------------------------------------------------------------------------&lt;/span&gt;
 &lt;span class="s1"&gt;'合进'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="s1"&gt;'安全'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt; &lt;span class="s1"&gt;'安全高效'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="s1"&gt;'将'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="s1"&gt;'整'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="s1"&gt;'方式'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt; &lt;span class="s1"&gt;'构建'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="s1"&gt;'流程'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="s1"&gt;'运'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="s1"&gt;'高效'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;-- 每个单词后面跟随了对应的位置信息&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;至此我们分词调整策略基本告一段落，主要做两个事情&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;修改 zhparser 的配置&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;修改自定义 &lt;code&gt;chinese_zh&lt;/code&gt; 分词策略所保留的词性&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;除此之外 zhparser 还支持自定义词库，所有的自定义词都放在了 &lt;code&gt;zhprs_custom_word&lt;/code&gt; 表里面，默认添加的自定义词的词性是 &lt;code&gt;(120, x, "unknown, 未知词")&lt;/code&gt;，可能用到的 sql 包含但不局限于如下：&lt;/em&gt;&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- 添加自定义词&lt;/span&gt;
&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;zhparser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zhprs_custom_word&lt;/span&gt; &lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'资金压力'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;-- 自定义词库也支持停止词功能，例如我们不希望词语'这是'单独作为一个分词，同样可以在自定义词库中插入对应的词语和控制符停止特定分词：&lt;/span&gt;
&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;zhparser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zhprs_custom_word&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'这是'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'!'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- 添加/删除自定义分词之后需要执行以下命令才能使词库生效&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;sync_zhprs_custom_word&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;-- 查询已存在的自定义词库&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;zhparser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zhprs_custom_word&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="排序"&gt;排序&lt;/h2&gt;
&lt;p&gt;PostgreSQL 有权重赋值的方法 &lt;a href="https://www.postgresql.org/docs/current/textsearch-controls.html" rel="nofollow" target="_blank" title=""&gt;&lt;code&gt;setweight&lt;/code&gt;&lt;/a&gt; 当然在 &lt;a href="https://github.com/Casecommons/pg_search" rel="nofollow" target="_blank" title=""&gt;pg_search&lt;/a&gt; 中也集成了该接口，便于直接使用。&lt;/p&gt;

&lt;p&gt;权重设置分别可以设定为 &lt;code&gt;A&lt;/code&gt; &lt;code&gt;B&lt;/code&gt; &lt;code&gt;C&lt;/code&gt; &lt;code&gt;D&lt;/code&gt;，默认值为 A&lt;/p&gt;

&lt;p&gt;假设权重用数字来评判的话（满分为 1 分）他们之间的梯度关系如下所示：&lt;/p&gt;
&lt;table class="table table-bordered table-striped"&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;th&gt;权重&lt;/th&gt;
&lt;th&gt;对应系数&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;0.4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;0.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;0.1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;--- 设置权重为 A&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;ts_rank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;setweight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to_tsvector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chinese_zh'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'这种将安全高效整合进研发和运维流程中的安全构建方式'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'A'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to_tsquery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chinese_zh'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'高效'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ts_rank&lt;/span&gt;
&lt;span class="c1"&gt;-----------&lt;/span&gt;
 &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;6079271&lt;/span&gt;

&lt;span class="c1"&gt;--- 设置权重为 B&lt;/span&gt;

&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;ts_rank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;setweight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to_tsvector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chinese_zh'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'这种将安全高效整合进研发和运维流程中的安全构建方式'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'B'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to_tsquery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chinese_zh'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'高效'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ts_rank&lt;/span&gt;
&lt;span class="c1"&gt;------------&lt;/span&gt;
 &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;24317084&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;--- 设置权重为 C&lt;/span&gt;

&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;ts_rank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;setweight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to_tsvector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chinese_zh'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'这种将安全高效整合进研发和运维流程中的安全构建方式'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'C'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to_tsquery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chinese_zh'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'高效'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ts_rank&lt;/span&gt;
&lt;span class="c1"&gt;------------&lt;/span&gt;
 &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;12158542&lt;/span&gt;

&lt;span class="c1"&gt;--- 设置权重为 D&lt;/span&gt;

&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;ts_rank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;setweight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to_tsvector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chinese_zh'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'这种将安全高效整合进研发和运维流程中的安全构建方式'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'D'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to_tsquery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chinese_zh'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'高效'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ts_rank&lt;/span&gt;
&lt;span class="c1"&gt;------------&lt;/span&gt;
 &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;06079271&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样的话我们便可以将文章的标题、描述、内容的权重分别设置为 A, B, C，以此算出一个综合的分数来做排序。但这种计算出来的分数只会和&lt;code&gt;词频&lt;/code&gt;相关。&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- A 代表权重，0 代表使用的关注度配置&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;ts_rank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;setweight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to_tsvector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chinese_zh'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'高效'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'A'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to_tsquery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chinese_zh'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'高效'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ts_rank&lt;/span&gt;
&lt;span class="c1"&gt;-----------&lt;/span&gt;
 &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;6079271&lt;/span&gt;
&lt;span class="c1"&gt;--  即使文档长度很小，最终计算出来的分数依然是 0.6079271&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;由于较长的文档包含查询词的几率更高，因此可能还需要考虑文档的长度，例如具有五个搜索词实例的一百字文档可能比具有五个搜索词实例的千字文档更相关。&lt;/p&gt;

&lt;p&gt;所以在此基础上我们需要引入 PostgreSQL 的 &lt;a href="https://www.postgresql.org/docs/current/textsearch-controls.html#TEXTSEARCH-RANKING" rel="nofollow" target="_blank" title=""&gt;normalization&lt;/a&gt; 参数&lt;/p&gt;

&lt;p&gt;具体怎么配置需要根据业务去调整，我们主要根据文档的长度做了些调整。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#   normalization 查询结果关注度:&lt;/span&gt;
&lt;span class="c1"&gt;#   0（缺省）表示跟长度大小没有关系&lt;/span&gt;
&lt;span class="c1"&gt;#   1 表示关注度（rank）除以文档长度的对数+1&lt;/span&gt;
&lt;span class="c1"&gt;#   2 表示关注度除以文档的长度&lt;/span&gt;
&lt;span class="c1"&gt;#   4 表示关注度除以范围内的平均谐波距离，只能使用ts_rank_cd实现。&lt;/span&gt;
&lt;span class="c1"&gt;#   8 表示关注度除以文档中唯一分词的数量&lt;/span&gt;
&lt;span class="c1"&gt;#   16 表示关注度除以唯一分词数量的对数+1&lt;/span&gt;
&lt;span class="c1"&gt;#   32 表示关注度除以本身+1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;测试一下长文本（由于文本太长这里就不贴出来了）和短文本之间的使用不同的 &lt;code&gt;normalization&lt;/code&gt;之后分数的差距。&lt;/p&gt;
&lt;table class="table table-bordered table-striped"&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;th&gt;文本长度&lt;/th&gt;
&lt;th&gt;normalization&lt;/th&gt;
&lt;th&gt;分数&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3887&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0.6079271&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1087&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0.6079271&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3887&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0.057773568&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1087&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0.06928112&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3887&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0.00041355583&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1087&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0.0013911375&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;相对来说 normalization 为 1 时，分数变化随着文章长度越长，变化曲率越平滑。&lt;/p&gt;

&lt;p&gt;至此我们排序策略基本告一段落，主要做两个事情&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;为文章的标题、描述、内容分别设置不同的权重&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;设置对应的 normalization 值&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;当然 &lt;a href="https://github.com/Casecommons/pg_search" rel="nofollow" target="_blank" title=""&gt;pg_search&lt;/a&gt; 上面还有更多的开箱即用的搜索的配置，这里就不再一一阐述了&lt;/p&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/hightman/scws" rel="nofollow" target="_blank" title=""&gt;SCWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/amutu/zhparser/tree/master" rel="nofollow" target="_blank" title=""&gt;zhparser&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ruby-china.org/topics/38153" title=""&gt;Postgres Fulltext Search (一)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ruby-china.org/topics/42047" title=""&gt;Postgres Full Text Search with Docker Compose&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;【实操系列】如何通过云原生数据仓库实现“一站式全文检索”业务（链接触发到敏感词，原文可能需要自行搜索一下）&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;</description>
      <author>SuMingXuan</author>
      <pubDate>Fri, 10 Nov 2023 20:49:44 +0800</pubDate>
      <link>https://ruby-china.org/topics/43468</link>
      <guid>https://ruby-china.org/topics/43468</guid>
    </item>
    <item>
      <title>simple_combine_xls - 让你合并表格就像画图一样</title>
      <description>&lt;h2 id="使用"&gt;使用&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/SuMingXuan/simple_combine_xls" rel="nofollow" target="_blank" title=""&gt;simple_combine_xls&lt;/a&gt; 让你合并表格就像画图一样&lt;/p&gt;

&lt;p&gt;在使用 simple_combine_xls 之前你必须得知道 ruby 中的 &lt;a href="https://apidock.com/ruby/Object/object_id" rel="nofollow" target="_blank" title=""&gt;object_id&lt;/a&gt; 概念&lt;/p&gt;

&lt;p&gt;没错 simple_combine_xls 是基于你分配的 &lt;code&gt;object_id&lt;/code&gt; 去合并的单元格，只要单元格的 &lt;code&gt;object_id&lt;/code&gt; 相同就会合并在一起&lt;/p&gt;

&lt;p&gt;如果你了解 &lt;code&gt;object_id&lt;/code&gt; 之后就能很快的去合并一个单元格&lt;/p&gt;
&lt;h2 id="示例"&gt;示例&lt;/h2&gt;
&lt;p&gt;你必须传一个二维数组给 simple_combine_xls&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;city1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;city2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;city3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"成都"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"南充"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"自贡"&lt;/span&gt;
&lt;span class="n"&gt;spec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"特色"&lt;/span&gt;
&lt;span class="c1"&gt;# menu1, menu2, menu3 的 object_id 都是不同的&lt;/span&gt;
&lt;span class="n"&gt;menu1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;menu2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;menu3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"菜单"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"菜单"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"菜单"&lt;/span&gt;
&lt;span class="n"&gt;scenic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"景点"&lt;/span&gt;
&lt;span class="c1"&gt;# 下面的 nil 将不会合并在一起&lt;/span&gt;
&lt;span class="n"&gt;datas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;city1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="n"&gt;menu1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s2"&gt;"串串"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="n"&gt;scenic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="s2"&gt;"春熙路"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;city1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="n"&gt;menu1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="n"&gt;scenic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="s2"&gt;"黄龙溪"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;city1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="n"&gt;menu1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s2"&gt;"火锅"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="n"&gt;scenic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"各种免费景点"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;city2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="n"&gt;menu2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s2"&gt;"米粉"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="n"&gt;scenic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s2"&gt;"蓝天网吧"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;city2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="n"&gt;menu2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s2"&gt;"锅盔"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="n"&gt;scenic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s2"&gt;"鼎盛网吧"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;city2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="n"&gt;menu2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="n"&gt;scenic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s2"&gt;"五星网吧"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;city2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="n"&gt;menu2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="n"&gt;scenic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s2"&gt;"各种网吧"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;city3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="n"&gt;menu3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="s2"&gt;"鲜锅兔"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="n"&gt;scenic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="s2"&gt;"7天酒店"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;city3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="n"&gt;menu3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="s2"&gt;"冷吃兔"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="n"&gt;scenic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s2"&gt;"汉庭酒店"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;city3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="n"&gt;menu3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="s2"&gt;"各种兔"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="n"&gt;scenic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;city3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="n"&gt;menu3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"富顺豆花"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="n"&gt;scenic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用 &lt;code&gt;drawing&lt;/code&gt; 方法去合并单元格&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;simple_combine_xls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;SimpleCombineXls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;simple_combine_xls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;drawing&lt;/span&gt;

&lt;span class="c1"&gt;# 合并之后 simple_combine_xls.xls 其实就是一个 spreadsheet&lt;/span&gt;
&lt;span class="n"&gt;simple_combine_xls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt; &lt;span class="s1"&gt;'./asd.xls'&lt;/span&gt;

&lt;span class="c1"&gt;# 如果你想对表格进行一个样式操作请查看 https://github.com/zdavatz/spreadsheet&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上代码 将会生成这样的单元格&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/SuMingXuan/5d6eab6e-df53-47ba-8a3a-4578d9f8f37d.jpg!large" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="注意"&gt;注意&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;simple_combine_xls 将会吧所有的对象都转化成字符串去操作&lt;/li&gt;
&lt;li&gt;simple_combine_xls 默认的占位符是 &lt;code&gt;" "&lt;/code&gt; (一个空格)&lt;/li&gt;
&lt;li&gt;在 ruby 中空字符串的 object_id 是一致的，所以在你需要考虑到 &lt;code&gt;nil.to_s&lt;/code&gt; 可能会合并一些单元格&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="vi"&gt;@str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;
&lt;span class="n"&gt;arr1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="vi"&gt;@str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;arr2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;# 对于 simple_combine_xls 来说 arr1 和 arr2 是完全不同的&lt;/span&gt;
&lt;span class="c1"&gt;# 因为 arr1.map(&amp;amp;:object_id) != arr2.map(&amp;amp;:object_id)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>SuMingXuan</author>
      <pubDate>Fri, 26 Mar 2021 13:37:13 +0800</pubDate>
      <link>https://ruby-china.org/topics/41082</link>
      <guid>https://ruby-china.org/topics/41082</guid>
    </item>
    <item>
      <title>Logisticed - 轻松记录操作人员和操作时间</title>
      <description>&lt;p&gt;很多系统的数据变更状态都可能会记录变更的操作人以及操作时间。写这个的原因是没有找到相关功能的 gem，于是自己写了这个 gem。也希望对部分有需求的开发者们有帮助&lt;/p&gt;

&lt;p&gt;补充更新： &lt;code&gt;audited&lt;/code&gt;  更侧重于对历史数据的收集， &lt;code&gt;logisticed&lt;/code&gt;  更侧重于对精准数据的变更记录，侧重点不一样。&lt;/p&gt;
&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/SuMingXuan/logisticed" rel="nofollow" target="_blank" title=""&gt;Logisticed&lt;/a&gt; 可以让你在 Controller 中无感知的记录 &lt;code&gt;操作人&lt;/code&gt; 和 &lt;code&gt;操作时间&lt;/code&gt; （其实也是模仿 &lt;a href="https://github.com/collectiveidea/audited/" rel="nofollow" target="_blank" title=""&gt;audited&lt;/a&gt; 去实现的）&lt;/p&gt;
&lt;h2 id="Installation"&gt;Installation&lt;/h2&gt;
&lt;p&gt;Add this line to your application's Gemfile:&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'logisticed'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, from your Rails app directory, create the &lt;code&gt;logistics&lt;/code&gt; table:&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;rake logisticed_migration:install:migrations
&lt;span class="nv"&gt;$ &lt;/span&gt;rails db:migrate
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="Usage"&gt;Usage&lt;/h2&gt;
&lt;p&gt;你只需要告诉 &lt;code&gt;logisticed&lt;/code&gt; 需要监听什么字段，并且被修改为什么值的时候就行了。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Page&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;logisticed&lt;/span&gt; &lt;span class="ss"&gt;:status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;values: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:active&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:archived&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# 他将会为你提供 `active_at`、 `active_by`、 `archived_at`、 `archived_by` 这几个方法，为你提供某个状态最近的操作历史&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果在 model 中定义了枚举类型的字段，也可以在定义枚举的下面直接添加 &lt;code&gt;logisticed&lt;/code&gt;，他会自动为你监听枚举的所有值，同时 logisticed 支持 &lt;code&gt;only&lt;/code&gt; 和 &lt;code&gt;except&lt;/code&gt; 这两个参数&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Page&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;enum&lt;/span&gt; &lt;span class="ss"&gt;status: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:draft&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:active&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:archived&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;logisticed&lt;/span&gt; &lt;span class="ss"&gt;:status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:active&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:archived&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在就已经可以监听所有的操作人和操作时间等信息了&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PagesController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
    &lt;span class="n"&gt;current_user&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;User name: 'sss'&amp;gt;&lt;/span&gt;
    &lt;span class="vi"&gt;@page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;Page status: 'draft'&amp;gt;&lt;/span&gt;
    &lt;span class="vi"&gt;@page.active&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
    &lt;span class="vi"&gt;@page.active_at&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; 2021-01-22 17:15:13 +0800&lt;/span&gt;
    &lt;span class="vi"&gt;@page.active_by&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;User name: 'sss'&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当然你也可以使用 &lt;code&gt;@page.logistics&lt;/code&gt; 得到 &lt;code&gt;@page&lt;/code&gt; 这条记录的所有变更流程，也可以使用 &lt;code&gt;@page.active_logistics&lt;/code&gt; 得到状态变为 active 的所有变更流程&lt;/p&gt;

&lt;p&gt;除此之外你也可以使用 &lt;code&gt;as_user&lt;/code&gt; 制定某个用户成为操作人员&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PagesController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
    &lt;span class="n"&gt;current_user&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;User name: 'sss'&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;last&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;User name: 'smx'&amp;gt;&lt;/span&gt;
    &lt;span class="no"&gt;Logisticed&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Logistic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="vi"&gt;@page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;Page status: 'draft'&amp;gt;&lt;/span&gt;
      &lt;span class="vi"&gt;@page.active&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
      &lt;span class="vi"&gt;@page.active_at&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; 2021-01-22 17:15:13 +0800&lt;/span&gt;
      &lt;span class="vi"&gt;@page.active_by&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;User name: 'smx'&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="setting"&gt;setting&lt;/h2&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/initializers/logisticed.rb&lt;/span&gt;

&lt;span class="no"&gt;Logisticed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current_user_method&lt;/span&gt;                &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:authenticated_user&lt;/span&gt;
  &lt;span class="c1"&gt;# if your table primary_key type is uuid&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logisticed_source_id_column_type&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:uuid&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logisticed_operator_id_column_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:uuid&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="项目地址"&gt;项目地址&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/SuMingXuan/logisticed" rel="nofollow" target="_blank"&gt;https://github.com/SuMingXuan/logisticed&lt;/a&gt;&lt;/p&gt;</description>
      <author>SuMingXuan</author>
      <pubDate>Wed, 27 Jan 2021 18:52:14 +0800</pubDate>
      <link>https://ruby-china.org/topics/40864</link>
      <guid>https://ruby-china.org/topics/40864</guid>
    </item>
    <item>
      <title>hash_map_attributes 将 JSON 类型的字段映射为具体的方法，方便 CRUD</title>
      <description>&lt;p&gt;项目地址：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/SuMingXuan/hash_map_attributes/" rel="nofollow" target="_blank"&gt;https://github.com/SuMingXuan/hash_map_attributes/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;写这个插件是因为目前在我做写业务的时候，需要预留一个 json 字段方便以后数据的扩展，并且方便 &lt;code&gt;CRUD&lt;/code&gt;。比如我有一个 &lt;code&gt;pages&lt;/code&gt; 表包含了一个 &lt;code&gt;jsonb&lt;/code&gt; 类型的字段（extra_data），&lt;code&gt;extra_data&lt;/code&gt;  里面可能存很多额外的属性或者是目前我们没有考虑到的属性。让我痛苦的是，对这种类型的字段操作 &lt;code&gt;CRUD&lt;/code&gt; 会让代码变得非常难看。&lt;/p&gt;
&lt;h2 id="Usage"&gt;Usage&lt;/h2&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Page&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
    &lt;span class="c1"&gt;# == Schema Information&lt;/span&gt;
    &lt;span class="c1"&gt;#&lt;/span&gt;
    &lt;span class="c1"&gt;# Table name: special_channels&lt;/span&gt;
    &lt;span class="c1"&gt;#&lt;/span&gt;
    &lt;span class="c1"&gt;#  id          :bigint           not null, primary key&lt;/span&gt;
    &lt;span class="c1"&gt;#  description :string&lt;/span&gt;
    &lt;span class="c1"&gt;#  title       :string&lt;/span&gt;
    &lt;span class="c1"&gt;#  extra_data  :jsonb&lt;/span&gt;
    &lt;span class="c1"&gt;#  created_at  :datetime         not null&lt;/span&gt;
    &lt;span class="c1"&gt;#  updated_at  :datetime         not null&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;HashMapAttributes&lt;/span&gt;
  &lt;span class="n"&gt;hash_map_attributes&lt;/span&gt; &lt;span class="ss"&gt;:image_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: :extra_data&lt;/span&gt;
  &lt;span class="n"&gt;hash_map_attributes&lt;/span&gt; &lt;span class="ss"&gt;:background_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;prefix: :content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: :extra_data&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;image_url: &lt;/span&gt;&lt;span class="s1"&gt;'http://www.image.com/example1.png'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;content_background_url: &lt;/span&gt;&lt;span class="s1"&gt;'http://www.image.com/example2.png'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;
&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;image_url&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; http://www.image.com/example1.png&lt;/span&gt;
&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;content_background_url&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; http://www.image.com/example2.png&lt;/span&gt;
&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;image_url: &lt;/span&gt;&lt;span class="s1"&gt;' http://www.image.com/example3.png'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;image_url&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; http://www.image.com/example3.png&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="查询"&gt;查询&lt;/h3&gt;
&lt;p&gt;如果是 jsonb 的话，那么则支持查询&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where_hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;image_url: &lt;/span&gt;&lt;span class="s1"&gt;'http://www.baidu.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;content_background_url: &lt;/span&gt;&lt;span class="s1"&gt;'http://www.baklib.com'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;控制台会打印如下查询语句&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="nv"&gt;"pages"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;"pages"&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extra_data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;'image_url'&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'http://www.baidu.com'&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extra_data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;'background_url'&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'http://www.baklib.com'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;补充：现在支持嵌套 json 的查询和修改了，但是取消了指定前缀的参数。&lt;/p&gt;</description>
      <author>SuMingXuan</author>
      <pubDate>Wed, 04 Nov 2020 18:29:20 +0800</pubDate>
      <link>https://ruby-china.org/topics/40547</link>
      <guid>https://ruby-china.org/topics/40547</guid>
    </item>
    <item>
      <title>erb 模板中的注释能否使用 proc 包装，达到快速注释的目的</title>
      <description>&lt;p&gt;假设有以下前端代码需要注释掉&lt;/p&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;...
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@post&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="vi"&gt;@post.title&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hello Word&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;能否使用 proc 将其包装（如下所示），而不去在每个&lt;code&gt;&amp;lt;%&lt;/code&gt; 后面添加#，这样对代码有没有影响&lt;/p&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;...
&lt;span class="c"&gt;&amp;lt;!-- 注释代码 --&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@post&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="vi"&gt;@post.title&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hello Word&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>SuMingXuan</author>
      <pubDate>Mon, 02 Sep 2019 14:28:33 +0800</pubDate>
      <link>https://ruby-china.org/topics/39008</link>
      <guid>https://ruby-china.org/topics/39008</guid>
    </item>
  </channel>
</rss>
