﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-agun 阿甘 ---分享,共同进步-随笔分类-数据库</title><link>http://www.blogjava.net/agun/category/30009.html</link><description>激情成就梦想，努力创造未来</description><language>zh-cn</language><lastBuildDate>Fri, 30 May 2008 21:39:02 GMT</lastBuildDate><pubDate>Fri, 30 May 2008 21:39:02 GMT</pubDate><ttl>60</ttl><item><title>PostgreSQL 8.3.1 全文检索(Full Text Search)</title><link>http://www.blogjava.net/agun/archive/2008/04/23/195086.html</link><dc:creator>agun</dc:creator><author>agun</author><pubDate>Wed, 23 Apr 2008 06:46:00 GMT</pubDate><guid>http://www.blogjava.net/agun/archive/2008/04/23/195086.html</guid><wfw:comment>http://www.blogjava.net/agun/comments/195086.html</wfw:comment><comments>http://www.blogjava.net/agun/archive/2008/04/23/195086.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/agun/comments/commentRss/195086.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/agun/services/trackbacks/195086.html</trackback:ping><description><![CDATA[<p><span style="color: red"><strong>&nbsp;PostgreSQL 8.3.1&nbsp; 全文检索</strong></span></p>
<p>在postgreSQL 8.3自带支持全文检索功能，在之前的版本中需要安装配置tsearch2才能使用，安转配置tsearch2就不再多说了，主要介绍一下8.3中自带全文检索功能。</p>
<p><span style="color: #00ff00"><strong>全文检索类型(Text Search Types)</strong><br />
</span><br />
postgreSQL设计支持全文检索，提供两个数据类型（tsvector,tsquery），并且通过动态检索自然语言文档的集合，定位到最匹配的查询结果。</p>
<p><strong>tsvector</strong></p>
<p>一个tsvector的值是唯一分词的分类列表，把一话一句词格式化为不同的词条，在进行分词处理的时候<br />
tsvector会自动去掉分词中重复的词条，按照一定的顺序装入。例如</p>
<p>SELECT 'a fat cat sat on a mat and ate a fat rat'::tsvector;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tsvector<br />
----------------------------------------------------<br />
&nbsp;'a' 'on' 'and' 'ate' 'cat' 'fat' 'mat' 'rat' 'sat'</p>
<p>从上面的例子可以看出 ，通过tsvector把一个字符串按照空格进行分词，分词的顺序是按照长短和字母来排序的。但是某些时候，我们为了让词条中包含空格或者符号，就需要对其使用引号。<br />
SELECT $$the lexeme '&nbsp;&nbsp;&nbsp; ' contains spaces$$::tsvector;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tsvector&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
-------------------------------------------<br />
&nbsp;'the' '&nbsp;&nbsp;&nbsp; ' 'lexeme' 'spaces' 'contains'</p>
<p>为了使用引号，我们可以使用双$$符号来避免混淆。<br />
并且词条位置常量可以附属于每个词条,例如：<br />
SELECT 'a:1 fat:2 cat:3 sat:4 on:5 a:6 mat:7 and:8 ate:9 a:10 fat:11 rat:12'::tsvector;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tsvector<br />
-------------------------------------------------------------------------------<br />
&nbsp;'a':1,6,10 'on':5 'and':8 'ate':9 'cat':3 'fat':2,11 'mat':7 'rat':12 'sat':4</p>
<p>这个位置信息通常就是当前文档中单词所处的位置，这个位置信息用于关注度的体现。位置信息常量的值的范围为1 到 16383。分词后，会把相同词条的位置记录到一个词条中。（如上所示）。<br />
词条通过权重可以使其所在位置促进它的标记。权重分为A,B,C,D,D为默认值可以不显示.</p>
<p>权重用于关系,体现文档结构是很有特色地.例如,通俗一点,就是相同的词条,但是词条所在位置的权重不一样,在一个文档中,标题和文本内容,在做全文检索排序功能时需要分配给这两个词不同的优先权,不同的权重标记.</p>
<p>理解tsvector类型是很重要的,不能只关注标准的应用.例如<br />
select 'The Fat Rats'::tsvector;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tsvector&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
--------------------<br />
&nbsp;'Fat' 'The' 'Rats'<br />
但是对于英文全文检索应用来说,上面的句子就是非标准化的,但是tsvector是不会知道的,为处理加工的文本应该通过使用to_tsvector函数来是之规格化,标注化的应用于搜索.</p>
<p>SELECT to_tsvector('english', 'The Fat Rats');&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp; to_tsvector&nbsp;&nbsp; <br />
-----------------<br />
&nbsp;'fat':2 'rat':3</p>
<p><br />
<strong>tsquery</strong></p>
<p>顾名思义,tsquery,表示的应该是查询相关的.tsquery是存储用于检索的词条.并且可以联合使用boolean 操作符来连接, &amp; (AND), | (OR), and ! (NOT). 使用括号(),可以强制分为一组.</p>
<p><br />
&nbsp;SELECT 'fat &amp; rat'::tsquery;<br />
&nbsp;&nbsp;&nbsp; tsquery&nbsp;&nbsp;&nbsp; <br />
---------------<br />
&nbsp;'fat' &amp; 'rat'</p>
<p>SELECT 'fat &amp; (rat | cat)'::tsquery;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tsquery&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
---------------------------<br />
&nbsp;'fat' &amp; ( 'rat' | 'cat' )</p>
<p>SELECT 'fat &amp; rat &amp; ! cat'::tsquery;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tsquery&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
------------------------<br />
&nbsp;'fat' &amp; 'rat' &amp; !'cat'<br />
同时,tsquery 在做搜索的时候,也可以使用权重,并且每个词都可以使用一个或者多个权重标记,这样在检索的时候,会匹配相同权重的信息.<br />
跟上面的tsvector ,相同tsquery也有一个to_tsquery函数.</p>
<p><span style="color: #00ff00"><strong>全文检索的 document</strong></span></p>
<p>document就是全文检索的搜索单元,在postgresql中全文检索匹配操作使用@@ 操作符,如果一个<br />
tsvector(document) 匹配到 tsquery(query)则返回true.</p>
<p>SELECT 'a fat cat sat on a mat and ate a fat rat'::tsvector @@ 'cat &amp; rat'::tsquery;<br />
&nbsp;?column?<br />
----------<br />
&nbsp;t<br />
我们在处理索引的时候还是要使用他们的函数如,<br />
SELECT to_tsvector('fat cats ate fat rats') @@ to_tsquery('fat &amp; rat');<br />
&nbsp;?column? <br />
----------<br />
&nbsp;t<br />
并且操作符 @@ 可以使用text作为tsvector和tsquery.如下操作符可以使使用的方法</p>
<p>tsvector @@ tsquery<br />
tsquery&nbsp; @@ tsvector<br />
text @@ tsquery<br />
text @@ text<br />
上面的前两种我们已经使用过了,但是后两种,<br />
text @@ tsquery 等同于 to_tsvector(x) @@ y. <br />
而 text @@ text 等同于 to_tsvector(x) @@ plainto_tsquery(y). </p>
<p><span style="color: #00ff00"><strong>表和索引<br />
</strong></span></p>
<p>前面介绍了如何在简单文本中进行全文检索匹配.下面部分将介绍如何检索表数据和使用索引.</p>
<p>检索一个表</p>
<p>在全文检索中不使用索引也是可以进行检索的,例如下面的简单例子,查询出title 从所有body中包含friend的行.</p>
<p>SELECT title<br />
FROM pgweb<br />
WHERE to_tsvector('english', body) @@ to_tsquery('english', 'friend');</p>
<p>复杂一点的例子:<br />
检索出最近的10个文档,在表中的title 和 body字段中包含 creat和table的titile.<br />
SELECT title<br />
FROM pgweb<br />
WHERE to_tsvector(title || body) @@ to_tsquery('create &amp; table')<br />
ORDER BY last_mod_date DESC LIMIT 10;</p>
<p><strong>建立索引</strong></p>
<p>我们可以通过创建gin索引来加速检索速度.例如</p>
<p>CREATE INDEX pgweb_idx ON pgweb USING gin(to_tsvector('english', body));</p>
<p>创建索引可以有多种方式.索引的创建甚至可以连接两个列: <br />
CREATE INDEX pgweb_idx ON pgweb USING gin(to_tsvector('english', title || body));<br />
另外的一种方式是创建一个单独的 tsvector列,然后使用to_tsvector函数把需要索引字段的数据联合在一起，比如列title和body，并且使用函数coalesce来确保字段为NULL的可以建立索引。<br />
如下：<br />
ALTER TABLE pgweb ADD COLUMN textsearchable_index_col tsvector;<br />
UPDATE pgweb SET textsearchable_index_col =<br />
&nbsp;&nbsp;&nbsp;&nbsp; to_tsvector('english', coalesce(title,'') || coalesce(body,''));<br />
然后，我们就可以创建倒排的索引<br />
CREATE INDEX textsearch_idx ON pgweb USING gin(textsearchable_index_col);<br />
索引创建完毕，我们就可以使用全文检索了。<br />
SELECT title<br />
FROM pgweb<br />
WHERE textsearchable_index_col @@ to_tsquery('create &amp; table')<br />
ORDER BY last_mod_date DESC LIMIT 10;</p>
<p>&nbsp;</p>
<p><span style="color: #00ff00"><strong>控制全文检索(Controlling Text Search)<br />
</strong></span><br />
为了实现全文检索，我们需要把一个文档创建一个tsvector 格式，并且通过tsquery实现用户的查询。<br />
因此，在查询中我们返回一个按照重要性排序的查询结果。</p>
<p><strong>分析文档(Parsing Documents)</strong><br />
<br />
postgresql 中提供了to_tsvector函数把文档处理成tsvector数据类型。（前面已经介绍过了）<br />
这个函数会将文本文档，分解成唯一的词条，并且还包括词条所在文本中的位置。（这里to_tsvector函数就不再多做介绍了）。<br />
其实在做分词是很重要的步骤，分词的操作直接关系到你的后来检索的结果。（后面再重要描述）<br />
在postgreSQL中默认的to_tsvector（'english',）配置默认的是英语。<br />
postgre 中还有一个函数 setweight ，要使用这个函数我们要引入一个概念，这个概念就是权重weight，什么是权重呢，字面上解释就是权衡一下哪个更重要，也就是说哪个更侧重一些。我们可以通过函数setweight来设置权重，postgre提供了四个A，B，C，D来分别表示不同权重级别，这个级别类型用来标记他们来自于文档中的不同部分，例如title和body。查询结果的关注度可以使用这个权重级别。如：<br />
UPDATE tt SET ti =<br />
&nbsp;&nbsp;&nbsp; setweight(to_tsvector(coalesce(title,'')), 'A')&nbsp;&nbsp;&nbsp; ||<br />
&nbsp;&nbsp;&nbsp; setweight(to_tsvector(coalesce(keyword,'')), 'B')&nbsp; ||<br />
&nbsp;&nbsp;&nbsp; setweight(to_tsvector(coalesce(abstract,'')), 'C') ||<br />
&nbsp;&nbsp;&nbsp; setweight(to_tsvector(coalesce(body,'')), 'D');</p>
<p><strong>搜索分析(Parsing Queries)</strong><br />
<br />
postgreSQL中提供了to_tsquery函数和plainto_tsquery函数，来处理分析搜索语句。</p>
<p>SELECT to_tsquery('english', 'The &amp; Fat &amp; Rats');<br />
&nbsp; to_tsquery&nbsp;&nbsp; <br />
---------------<br />
&nbsp;'fat' &amp; 'rat'</p>
<p>在搜索中tsquery中可以使用权重（weight）,在搜索词条中可以附加权重，并且匹配出来的查询结果也是必须在这个这个权重范围的。</p>
<p>SELECT to_tsquery('english', 'Fat | Rats:AB');<br />
&nbsp;&nbsp;&nbsp; to_tsquery&nbsp;&nbsp;&nbsp; <br />
------------------<br />
&nbsp;'fat' | 'rat':AB</p>
<p>从上面的例子可以看出，to_tsquery函数在处理查询文本的时候，查询文本的单个词之间要使用逻辑操作符（&amp; (AND), | (OR) and ! (NOT)）连接（或者使用括号）。例如 跟上面的例子相似</p>
<p>SELECT to_tsquery('english', 'Fat&nbsp; Rats');</p>
<p>如果要使执行上面的操作，就会报语法错误。<br />
然而plainto_tsquery函数却可以提供一个标准的tsquery，如上面的例子，plainto_tsquery会自动加上逻辑&amp;操作符。<br />
SELECT plainto_tsquery('english', 'Fat&nbsp; Rats');</p>
<p>&nbsp;plainto_tsquery <br />
-----------------<br />
&nbsp;'fat' &amp; 'rat'<br />
但是plainto_tsquery函数不能够识别逻辑操作符和权重标记。<br />
SELECT plainto_tsquery('english', 'The Fat &amp; Rats:C');<br />
&nbsp;&nbsp; plainto_tsquery&nbsp;&nbsp; <br />
---------------------<br />
&nbsp;'fat' &amp; 'rat' &amp; 'c'</p>
<p><strong>查询结果关注度(Ranking Search Results)</strong><br />
</p>
<p>相关度，就是试图测试衡量哪一个文档是检索中最关注的。因此我们把最匹配的文档现在在最前面。这样才能真正达到检索的准确度，postgresql提供两个相关的函数，ts_rank和ts_rank_cd.<br />
这两个函数的语法是<br />
ts_rank([ weights float4[], ] vector tsvector, query tsquery [, normalization integer ]) returns float4</p>
<p>ts_rank_cd([ weights float4[], ] vector tsvector, query tsquery [, normalization integer ]) returns float4</p>
<p>两个函数的第一个参数都是 权重(weight)，在前面已经讲了权重的概念。<br />
参数的格式为 {D-weight, C-weight, B-weight, A-weight} ，在使用函数的时候没有指定这个参数，postgre会默认指定参数为：{0.1, 0.2, 0.4, 1.0}<br />
这个参数应该理解为：单前检索的关键词（词条）在当前这个检索文档中的位置，如果这个词条在这个当前的位置权重高，那么他的相关度的值也会高。<br />
另外函数的最好一个参数是一个整型，这个参数是表示，这个参数指定文档大小影响相关度的程度。<br />
你可以指定一个或者多个例如（2|4）。<br />
这些参数的定义</p>
<p>0 (the default) ignores the document length <br />
表示跟长度大小没有关系<br />
1 divides the rank by 1 + the logarithm of the document length <br />
表示参数 关注度（rank）除以 文档长度的对数+1<br />
2 divides the rank by the document length <br />
表示 关注度 除以 文档的长度<br />
4 divides the rank by the mean harmonic distance between extents (this is implemented only by ts_rank_cd) <br />
表示 关注度 除以 文档长度的平均值，只能使用函数ts_rank_cd.<br />
8 divides the rank by the number of unique words in document <br />
表示 关注度 除以 文档中 唯一分词的数量<br />
16 divides the rank by 1 + the logarithm of the number of unique words in document <br />
表示关注度 除以 唯一分词数量的对数+1<br />
32 divides the rank by itself + 1 <br />
表示 关注度 除以 本身+1</p>
<p><br />
<strong>其他的一些特性</strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; length(vector tsvector) returns integer<br />
&nbsp;&nbsp;&nbsp; 这个函数返回当前索引字段的分词长度，就是分词的个数</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strip(vector tsvector) retzitor<br />
这个函数返回当前索引字段的数据不包括词的位置</p>
<p><br />
<span style="color: #00ff00"><strong>自动更新处理的触发器(Triggers for Automatic Updates)</strong></span><br />
</p>
<p>在我们作全文检索的时候，当我们使用单独的列来存储索引文件的时候，我们一定需要创建一个触发器，当涉及索引字段的其他列的内容改变的时候，索引文件也要相应的改变，postgre提供两个触发器可以实现该功能，也可以自定义触发器。</p>
<p>这两个触发器的为：<br />
&nbsp;&nbsp;&nbsp; tsvector_update_trigger(tsvector_column_name, config_name, text_column_name [, ... ])<br />
&nbsp;&nbsp;&nbsp; tsvector_update_trigger_column(tsvector_column_name, config_column_name, text_column_name [, ... ])</p>
<p>这个函数可以自动把一个或者多个文本字段，计算生成索引字段。例如</p>
<p>我们创建一个表<br />
CREATE TABLE messages (<br />
&nbsp;&nbsp;&nbsp; title&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; text,<br />
&nbsp;&nbsp;&nbsp; body&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; text,<br />
&nbsp;&nbsp;&nbsp; tsv&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tsvector//索引字段<br />
);</p>
<p>CREATE TRIGGER tsvectorupdate BEFORE INSERT OR UPDATE<br />
ON messages FOR EACH ROW EXECUTE PROCEDURE<br />
tsvector_update_trigger(tsv, 'pg_catalog.english', title, body);<br />
创建触发器，字段title和body都是文本字段，他们索引后的字段为tsv,这里使用postgre自带的分词规则pg_catalog.english。<br />
向表中插入一条数据。<br />
INSERT INTO messages VALUES('title here', 'the body text is here');</p>
<p>SELECT * FROM messages;<br />
&nbsp;&nbsp; title&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; body&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tsv&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
------------+-----------------------+----------------------------<br />
&nbsp;title here | the body text is here | 'bodi':4 'text':5 'titl':1<br />
可以看到tsv字段自动加入的数据，并且经过tsvector处理。<br />
接下来我们测试一下检索<br />
SELECT title, body FROM messages WHERE tsv @@ to_tsquery('title &amp; body');<br />
上面这个查询，查不到结果。<br />
SELECT title, body FROM messages WHERE tsv @@ to_tsquery('english','title &amp; body');<br />
&nbsp;&nbsp; title&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; body&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
------------+-----------------------<br />
&nbsp;title here | the body text is here<br />
注意: 看上面的查询条件，在进行全文检索的时候，在创建索引时，使用的分词方式，与检索时使用的分词方式一定要想同，否则查询的结果就会有问题。</p>
<p>创建触发器后，不论title或者body那个字段改变，都会自动反射给tsv,索引会自动更新。</p>
<p>上面这中自带的触发器很有局限性，比如说，在建立索引的时候title和body要有不同的权重，上面的触发器就能达到我们想要的效果，下面是一个 pl/pgsql 触发器。</p>
<p>CREATE FUNCTION messages_trigger() RETURNS trigger AS $$<br />
begin<br />
&nbsp; new.tsv :=<br />
&nbsp;&nbsp;&nbsp;&nbsp; setweight(to_tsvector('pg_catalog.english', coalesce(new.title,'')), 'A') ||<br />
&nbsp;&nbsp;&nbsp;&nbsp; setweight(to_tsvector('pg_catalog.english', coalesce(new.body,'')), 'D');<br />
&nbsp; return new;<br />
end<br />
$$ LANGUAGE plpgsql;</p>
<p>CREATE TRIGGER tsvectorupdate BEFORE INSERT OR UPDATE<br />
ON messages FOR EACH ROW EXECUTE PROCEDURE messages_trigger();</p>
<p><span style="color: #00ff00"><strong>索引统计函数<br />
</strong></span></p>
<p>&nbsp;ts_stat(sqlquery text, [ weights text, ] OUT word text, OUT ndoc integer, OUT nentry integer) </p>
<p>返回的是统计的纪录</p>
<p>word text — 索引中的词条</p>
<p>ndoc integer — 词条在索引中出现的次数</p>
<p>nentry integer — 词条在文档中出现的总次数</p>
<p>例如：</p>
<p>SELECT * FROM ts_stat('SELECT tsv FROM messages')<br />
ORDER BY nentry DESC, ndoc DESC, word<br />
LIMIT 10;</p>
<p>查询的结果为</p>
<p>&nbsp; word&nbsp;&nbsp;&nbsp;&nbsp; ndoc&nbsp; nentry</p>
<p>&nbsp; test&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3<br />
&nbsp; title&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2<br />
&nbsp; test&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2<br />
&nbsp; body&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1</p>
<p>上面可以看到，通过ts_stat函数就可以看到索引列中的分词的情况。</p>
<p>&nbsp;</p>
<p><strong style="color: #00ff00">词典(Dictionaries)</strong><br />
<br />
词典就是被用来过滤掉一些不被关注的词（在检索的时候），并且对词句规格化，是为了相同的词在不同的来源的文档中可以被匹配。一个成功分词（格式化的）的词称为词条。除了能提高检索的质量外，分词的规格化，过滤词，还能够减少文档索引的大小，这样可以提高性能。标准化的词也不能总是符合语言学意义，并且总是依赖于应用所在的环境。<br />
简单举例：<br />
例如一些颜色名称，将会被替换成其相对应的16进制的值，如 red,green,blue -&gt;FF0000, 00FF00, 0000FF 等。<br />
如果要制定小数，我们可以去掉一些小数的位数，来减少范围。如 3.14159265359 ,3.1415926,这两个小数如果是保留小数点后两位小数，那么格式化后他们的值将都是 3.14。</p>
<p>postgresql提供了一些预定义的词典面向多种语言的，并且还有几个预定义的模版，可以根据用户的需要自定义词典。</p>
<p><strong>屏蔽词(Stop Words)</strong><br />
stop words 是一个很普遍并且在每个文档中几乎都能出现的的词，并且这个词没有实际的意义，因此在全文检索的文档中他么将被忽略。例如 英文文本内容中单词 像 a 和like，他们不需要存储在索引中，但是他会影响词所在文档的位置。<br />
SELECT to_tsvector('english','in the list of stop words');<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to_tsvector<br />
----------------------------<br />
&nbsp;'list':3 'stop':5 'word':6<br />
并且相关度的计算与是否存在stop words是十分不同的,如: <br />
SELECT ts_rank_cd (to_tsvector('english','in the list of stop words'), to_tsquery('list &amp; stop'));<br />
&nbsp;ts_rank_cd<br />
------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0.05</p>
<p>SELECT ts_rank_cd (to_tsvector('english','list stop words'), to_tsquery('list &amp; stop'));<br />
&nbsp;ts_rank_cd<br />
------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0.1<br />
<br />
<strong>简单词典<br />
</strong><br />
使用简单词典,自定义词典,如:</p>
<p>CREATE TEXT SEARCH DICTIONARY public.simple_dict (<br />
&nbsp;&nbsp;&nbsp; TEMPLATE = pg_catalog.simple,<br />
&nbsp;&nbsp;&nbsp; STOPWORDS = english<br />
);</p>
<p>上面例子中的 english是表示的stop words的名字,这个stop words的全名因该是$sharedir/tsearch_data/english.stop,$sharedir也就是postgresql的安装目录下.现在我们使用一下新建的词典.如:<br />
SELECT ts_lexize('public.simple_dict','YeS');<br />
&nbsp;ts_lexize<br />
-----------<br />
&nbsp;{yes}</p>
<p>SELECT ts_lexize('public.simple_dict','The');<br />
&nbsp;ts_lexize<br />
-----------<br />
&nbsp;{}<br />
还有几个postgresql中自带的词典, Simple Dictionary,Synonym Dictionary<br />
,Thesaurus Dictionary<br />
,Ispell Dictionary<br />
,Snowball Dictionary<br />
这里不再详细介绍了.</p>
<p>&nbsp;</p>
<p><span style="color: #00ff00"><br />
<strong>全文检索的测试和调试<br />
</strong></span><br />
<strong>ts_debug函数用来调试全文检索的<br />
<br />
</strong>这个函数显示的是文档的每个词条通过基本词典的分析和处理的信息。<br />
这个函数返回的信息为：<br />
alias text — short name of the token type <br />
文本别名-词的类型名称<br />
description text — description of the token type <br />
描述-描述词的类型<br />
token text — text of the token <br />
词内容-词的文本内容<br />
dictionaries regdictionary[] — the dictionaries selected by the configuration for this token type <br />
词典-词的配置所选择的词典<br />
dictionary regdictionary — the dictionary that recognized the token, or NULL if none did <br />
词典<br />
lexemes text[] — the lexeme(s) produced by the dictionary that recognized the token, or NULL if none did; an empty array ({}) means it was recognized as a stop word <br />
处理后的词条</p>
<p>Here is a simple example: </p>
<p>SELECT * FROM ts_debug('english','a fat&nbsp; cat sat on a mat - it ate a fat rats');<br />
&nbsp;&nbsp; alias&nbsp;&nbsp; |&nbsp;&nbsp; description&nbsp;&nbsp; | token |&nbsp; dictionaries&nbsp; |&nbsp; dictionary&nbsp; | lexemes <br />
-----------+-----------------+-------+----------------+--------------+---------<br />
&nbsp;asciiword | Word, all ASCII | a&nbsp;&nbsp;&nbsp;&nbsp; | {english_stem} | english_stem | {}<br />
&nbsp;blank&nbsp;&nbsp;&nbsp;&nbsp; | Space symbols&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | {}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | <br />
&nbsp;asciiword | Word, all ASCII | fat&nbsp;&nbsp; | {english_stem} | english_stem | {fat}<br />
&nbsp;blank&nbsp;&nbsp;&nbsp;&nbsp; | Space symbols&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | {}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | <br />
&nbsp;asciiword | Word, all ASCII | cat&nbsp;&nbsp; | {english_stem} | english_stem | {cat}<br />
&nbsp;blank&nbsp;&nbsp;&nbsp;&nbsp; | Space symbols&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | {}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | <br />
&nbsp;asciiword | Word, all ASCII | sat&nbsp;&nbsp; | {english_stem} | english_stem | {sat}<br />
&nbsp;blank&nbsp;&nbsp;&nbsp;&nbsp; | Space symbols&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | {}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | <br />
&nbsp;asciiword | Word, all ASCII | on&nbsp;&nbsp;&nbsp; | {english_stem} | english_stem | {}<br />
&nbsp;blank&nbsp;&nbsp;&nbsp;&nbsp; | Space symbols&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | {}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | <br />
&nbsp;asciiword | Word, all ASCII | a&nbsp;&nbsp;&nbsp;&nbsp; | {english_stem} | english_stem | {}<br />
&nbsp;blank&nbsp;&nbsp;&nbsp;&nbsp; | Space symbols&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | {}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | <br />
&nbsp;asciiword | Word, all ASCII | mat&nbsp;&nbsp; | {english_stem} | english_stem | {mat}<br />
&nbsp;blank&nbsp;&nbsp;&nbsp;&nbsp; | Space symbols&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | {}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | <br />
&nbsp;blank&nbsp;&nbsp;&nbsp;&nbsp; | Space symbols&nbsp;&nbsp; | -&nbsp;&nbsp;&nbsp;&nbsp; | {}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | <br />
&nbsp;asciiword | Word, all ASCII | it&nbsp;&nbsp;&nbsp; | {english_stem} | english_stem | {}<br />
&nbsp;blank&nbsp;&nbsp;&nbsp;&nbsp; | Space symbols&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | {}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | <br />
&nbsp;asciiword | Word, all ASCII | ate&nbsp;&nbsp; | {english_stem} | english_stem | {ate}<br />
&nbsp;blank&nbsp;&nbsp;&nbsp;&nbsp; | Space symbols&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | {}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | <br />
&nbsp;asciiword | Word, all ASCII | a&nbsp;&nbsp;&nbsp;&nbsp; | {english_stem} | english_stem | {}<br />
&nbsp;blank&nbsp;&nbsp;&nbsp;&nbsp; | Space symbols&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | {}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | <br />
&nbsp;asciiword | Word, all ASCII | fat&nbsp;&nbsp; | {english_stem} | english_stem | {fat}<br />
&nbsp;blank&nbsp;&nbsp;&nbsp;&nbsp; | Space symbols&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | {}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | <br />
&nbsp;asciiword | Word, all ASCII | rats&nbsp; | {english_stem} | english_stem | {rat}</p>
<p><br />
<strong>分析器测试(ts_parse)</strong><br />
</p>
<p>ts_parse函数分析文档并且返回一串记录，每一个解析后的词都有一个tokid，和的分词。如</p>
<p>SELECT * FROM ts_parse('default', '123 - a number');<br />
&nbsp;tokid | token<br />
-------+--------<br />
&nbsp;&nbsp;&nbsp; 22 | 123<br />
&nbsp;&nbsp;&nbsp; 12 |<br />
&nbsp;&nbsp;&nbsp; 12 | -<br />
&nbsp;&nbsp;&nbsp;&nbsp; 1 | a<br />
&nbsp;&nbsp;&nbsp; 12 |<br />
&nbsp;&nbsp;&nbsp;&nbsp; 1 | number</p>
<p><br />
<span style="color: #00ff00"><strong>gist 和 gin的索引类型(GiST and GIN Index Types)</strong></span><br />
<br />
这两种索引都能用在提高全文检索的速度，注意全文检索不一定非要使用索引，但是万一当一个字段被固定规律搜索时，使用索引将会有很好的效果。</p>
<p>CREATE INDEX name ON table USING gist(column);<br />
创建索引 gist 索引字段的类型可以是 tsvector 或者 tsquery.<br />
&nbsp;<br />
CREATE INDEX name ON table USING gin(column);<br />
创建索引 gin 索引字段的类型必须是 tsvector;</p>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/agun/aggbug/195086.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/agun/" target="_blank">agun</a> 2008-04-23 14:46 <a href="http://www.blogjava.net/agun/archive/2008/04/23/195086.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>POSTGIS常用函数</title><link>http://www.blogjava.net/agun/archive/2008/03/24/188289.html</link><dc:creator>agun</dc:creator><author>agun</author><pubDate>Mon, 24 Mar 2008 08:46:00 GMT</pubDate><guid>http://www.blogjava.net/agun/archive/2008/03/24/188289.html</guid><wfw:comment>http://www.blogjava.net/agun/comments/188289.html</wfw:comment><comments>http://www.blogjava.net/agun/archive/2008/03/24/188289.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/agun/comments/commentRss/188289.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/agun/services/trackbacks/188289.html</trackback:ping><description><![CDATA[<p><span style="color: red">Management Functions </span></p>
<p><span style="color: red">1,基本操作函数</span></p>
<p><br />
<span style="color: #00ff00">AddGeometryColumn(&lt;schema_name&gt;, &lt;table_name&gt;, &lt;column_name&gt;, &lt;srid&gt;, &lt;type&gt;, &lt;dimension&gt;)</span><br />
给一个已存在属性数据表增加一个几何字段(geomtry column)。schema_name 指表的模式的名字，srid 必须是一个整数指对应于 SPATIAL_REF_SYS 表，type必须是一个大写的字符串，用来描述几何类型，例如：'POLYGON' 或者 'MULTILINESTRING'。</p>
<p><span style="color: #00ff00">DropGeometryColumn(&lt;schema_name&gt;, &lt;table_name&gt;, &lt;column_name&gt;)</span><br />
从一个空间数据表中删除一个几何字段。</p>
<p><span style="color: #00ff00">ST_SetSRID(geometry, integer)</span><br />
给一个几何对象(geometry)设置一个整型的SRID，对于在一个范围内的查询非常有用。&nbsp;<br />
&nbsp; <br />
<span style="color: #ff0000">2. Geometry Relationship Functions <br />
&nbsp;&nbsp; 几何空间数据关系函数 </span></p>
<p><span style="color: #00ff00">ST_Distance(geometry, geometry) </span><br />
返回两个几何对象的距离（笛卡儿距离），不使用索引。&nbsp;<br />
&nbsp; <br />
<span style="color: #00ff00">ST_DWithid(geometry, geometry, float) </span><br />
如果一个几何对象(geometry)在另一个几何对象描述的距离(float)内，返回TRUE。如果有索引，会用到索引。 <br />
<br />
<span style="color: #00ff00">ST_Equals(geometry, geometry)</span><br />
如果两个空间对象相等，则返回TRUE。用这个函数比用&#8220;=&#8221;更好，例如：<br />
equals('LINESTRING(0 0, 10 10)','LINESTRING(0 0, 5 5, 10 10)') 返回 TRUE。</p>
<p><span style="color: #00ff00">ST_Disjoint(geometry, geometry)</span><br />
如果两个对象不相连，则返回TRUE。不要使用GeometryCollection作为参数。<br />
<br />
<span style="color: #00ff00">ST_Intersects(geometry, geometry)</span><br />
判断两个几何空间数据是否相交,如果相交返回true,不要使用GeometryCollection作为参数。<br />
Intersects(g1, g2 ) --&gt; Not (Disjoint(g1, g2 ))<br />
不使用索引可以用_ST_Intersects.</p>
<p><span style="color: #00ff00">ST_Touches(geometry, geometry)</span><br />
如果两个几何空间对象存在接触，则返回TRUE。不要使用GeometryCollection作为参数。<br />
a.Touches(b) -&gt; (I(a) intersection I(b) = {empty set} ) and (a intersection b) not empty<br />
不使用索引可以用_ST_Touches.</p>
<p><span style="color: #00ff00">ST_Crosses(geometry, geometry)</span><br />
如果两个几何空间对象存在交叉，则返回TRUE。不要使用GeometryCollection作为参数。<br />
不使用索引可以用_ST_Crosses.</p>
<p><span style="color: #00ff00">ST_Within(geometry A, geometry B)</span><br />
如果几何空间对象A存在空间对象B中,则返回TRUE,不要使用GeometryCollection作为参数。<br />
不使用索引可以用_ST_Within</p>
<p><span style="color: #00ff00">ST_Overlaps(geometry, geometry)<br />
</span>如果两个几何空间数据存在交迭,则返回 TRUE,不要使用GeometryCollection作为参数。<br />
不使用索引可以用_ST_Overlaps.</p>
<p><span style="color: #00ff00">ST_Contains(geometry A, geometry B)</span><br />
如果几何空间对象A包含空间对象B,则返回 TRUE,不要使用GeometryCollection作为参数。<br />
这个函数类似于ST_Within(geometry B, geometry A)<br />
不使用索引可以用_ST_Contains.</p>
<p><span style="color: #00ff00">ST_Covers(geometry A, geometry B)<br />
</span>如果几何空间对象B中的所有点都在空间对象A中,则返回 TRUE。<br />
不要使用GeometryCollection作为参数。<br />
不使用索引可以用_ST_Covers.</p>
<p><span style="color: #00ff00">ST_CoveredBy(geometry A, geometry B)</span><br />
如果几何空间对象A中的所有点都在空间对象B中,则返回 TRUE。</p>
<p><span style="color: #ff0000">3,Geometry Processing Functions<br />
几何空间数据处理函数</span></p>
<p><span style="color: #00ff00">ST_Centroid(geometry)</span><br />
返回质心点,就是根据几何空间数据,活动该几何空间数据的中心点,返回一个空间点数据.</p>
<p><span style="color: #00ff00">ST_Area(geometry)</span><br />
如果几何空间数据为多边形,或者多多边形,则返回空间数据的外围(返回类型double precision) ;</p>
<p><span style="color: #00ff00">ST_Length(geometry)</span><br />
这个曲线在其相关的空间参考长度(返回类型double precision) ;</p>
<p><span style="color: #00ff00">ST_PointOnSurface(geometry)</span><br />
一定在几何空间线数据上的点，返回一个数据点<span style="color: #00ff00"></p>
<p><font style="background-color: #c7edcc">ST_Buffer(geometry, double, [integer])<br />
<span style="color: #000000">buffer操作一个很有用函数，<br />
这个函数的第一个参数是要操作的空间几何数据，第二个参数长度（距离），第三个参数为一个整型，<br />
这个函数返回一个空间数据类型，以当前第一个参数空间几何数据为参考点，返回小于等于距离的空间</span></font></p>
<p><span style="color: #000000">几何数据点，最后由这些点组成一个多边形空间数据，最后一个参数表示<br />
在组成一个1/4圆的有几个点分隔。也就是说如果最好一个参数为8那么这个最后组成的多边形就是32边</span></p>
<p><span style="color: #000000">的多边形，如果不指定这个参数，系统默认的是8<br />
注意：第二个参数，距离它的单位为空间数据单位（度），在运算时需要进行单位换算，最后转换成度</span></p>
<p><span style="color: #000000">，单位的换算关系如下：<br />
1英里= 63360 米<br />
1米=1/1852 海里<br />
1海里= 1/60度<br />
如果要进行具体的运算，需要进行一下单位换算，比如要求一个500米的范围，那么应该是</span></p>
<p><span style="color: #000000">500*1/1852*1/60（度）</span></p>
<p><font style="background-color: #c7edcc">ST_Envelope(geometry)<br />
<span style="color: #000000">这个函数可以返回mbr(空间最小外包矩形)，传入参数可以是point line polygon。</span></font></p>
<p><font style="background-color: #c7edcc"><br />
ST_extent(geometry set)<br />
<span style="color: #000000">这个函数可以对一个空间数据集进行操作，返回一个最小包含矩形（mbr）.<br />
如：SELECT EXTENT(GEOM) FROM GEOMTABLE GROUP BY CATEGORY<br />
</span></font></p>
<p><br />
ST_Difference(geometry A, geometry B)</span><br />
返回一个几何空间数据A不同于空间数据B的几何空间数据类型，不要使用GeometryCollection作为参数。<br />
也就是说，如果A为一个line,B也为一个line，那么他们返回的类型就是B把A分割的多线。<br />
如：<br />
select ST_AsEWKT(ST_Difference(geomfromText('LINESTRING(1 1,2 3,3 4,3 1)'),geomfromText('LINESTRING(2 0,2 2,5 2,3 1)')))<br />
返回的MULTILINESTRING((1 1,2 3,3 4,3 2),(3 2,3 1))<br />
如果是A和B都是一个POLYGON多边形，那么返回的就是多多边形，如果相交，那么返回的就是B把A分割，并且不再B中的多多边形。<br />
select ST_AsEWKT(ST_Difference(geomfromText('POLYGON((1 1,2 3,3 4,3 1,1 1))'),geomfromText('POLYGON((2 0,2 2,5 2,1 3,2 0))')))</p>
<p><span style="color: #00ff00">ST_Union(geometry, geometry)</span><br />
返回一个合并的几何空间数据，将两个几何空间数据合并为一个几何空间数据，或者GeometryCollection，不要使用GeometryCollection作为参数。</p>
<p><br />
<span style="color: #ff0000">4 ，Geometry Accessors</span></p>
<p><span style="color: #00ff00">ST_AsText(geometry)</span><br />
将几何空间数据，转换成容易理解的空间数据文本格式，<br />
例如：<br />
(0,0 0,1 1,1 1,0 0,0)<br />
转换后应该是这样的结果 POLYGON(0 0,0 1,1 1,1 0,0 0)</p>
<p><span style="color: #00ff00">ST_SRID(geometry)</span><br />
返回当前几何空间数据的SRID值</p>
<p><span style="color: #00ff00">ST_IsClosed(geometry)</span><br />
判断几何空间数据是否是闭合，就是判断起始点和终点坐标是相同的，如果是相同的返回true,否则返回false.</p>
<p><span style="color: #00ff00">ST_IsRing(geometry)</span><br />
这个函数参数的对象是line，判断起始点和终点坐标是否相同，<br />
如果闭合(这个曲线除了起始点和终点相同外，没有其他相交点)怎返回true,否则false,</p>
<p><span style="color: #00ff00">ST_NumPoints(geometry)</span><br />
返回几何空间数据lineString上的第一条线上点的个数。</p>
<p><br />
<span style="color: #00ff00">GeometryType(geometry)</span><br />
判断几何空间数据的类型。<br />
例如<br />
select GeometryType(geomfromText('MULTILINESTRING((1 1,2 3,3 4,3 1,2 1,1 1),(1 2,2 3,4 5))'))<br />
返回的类型为 MULTILINESTRING。</p>
<p><br />
&nbsp;</p>
<img src ="http://www.blogjava.net/agun/aggbug/188289.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/agun/" target="_blank">agun</a> 2008-03-24 16:46 <a href="http://www.blogjava.net/agun/archive/2008/03/24/188289.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>索引的使用</title><link>http://www.blogjava.net/agun/archive/2008/03/11/185384.html</link><dc:creator>agun</dc:creator><author>agun</author><pubDate>Tue, 11 Mar 2008 07:07:00 GMT</pubDate><guid>http://www.blogjava.net/agun/archive/2008/03/11/185384.html</guid><wfw:comment>http://www.blogjava.net/agun/comments/185384.html</wfw:comment><comments>http://www.blogjava.net/agun/archive/2008/03/11/185384.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/agun/comments/commentRss/185384.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/agun/services/trackbacks/185384.html</trackback:ping><description><![CDATA[<p>索引的简单使用说明：<br />
<br />
一.常用扫描方式：<br />
.全表扫描 <br />
&nbsp;全表扫描就是顺序地访问表中每条记录. <br />
.索引扫描　　<br />
索引唯一扫描(index unique scan) <br />
索引范围扫描(index range scan) <br />
索引全扫描(index full scan) <br />
索引快速扫描(index fast full scan)&nbsp; </p>
<p>1.索引唯一扫描(index unique scan) <br />
通过唯一索引查找一个数值经常返回单个ROWID。如果该唯一索引有多个列组成(即组合索引)，则至少要有组合索引的引导列参与到该查询中，如创建索引：create index index_test on building(name,status)。<br />
如：语句：<br />
select id from building where name='国际科技大厦'<br />
此语句可以使用该索引。如果该语句只返回一行，则存取方法称为索引唯一扫描。<br />
而语句：<br />
select name from building where status ='1'<br />
因为where条件没有用到索引的引导列。所以索引不生效。</p>
<p>2.索引范围扫描(index range scan) <br />
使用一个索引存取多行数据，同上面一样，如果索引是组合索引<br />
如:select id from building where name like 'H%' and status='1' 语句返回多行数据，此时的存取方法称为索引范围扫描。<br />
使用index rang scan的3种情况： <br />
(a) 在唯一索引列上使用了range操作符(&gt; &lt; &lt;&gt; &gt;= &lt;= between) <br />
(b) 在组合索引上，只使用部分列进行查询，导致查询出多行 <br />
(c) 对非唯一索引列上进行的任何查询。 </p>
<p>3. 全索引扫描(index full scan) <br />
SQL请求的全部列（column）必须驻留在索引树中；也就是说，SELECT和WHERE字句中的所有数据列必须存在于索引中。并且排序返回。 </p>
<p>4.索引快速扫描(index fast full scan) <br />
扫描索引中的所有的数据块，与 index full scan很类似，但是一个显著的区别就是它不对查询出的数据进行排序，即数据不是以排序顺序被返回。</p>
<p>&nbsp;</p>
<p>二.什么情况下应该建立索引<br />
1.表的主关键字(建立唯一索引)<br />
2.表的字段唯一约束<br />
3.直接条件查询的字段,在SQL中用于条件约束的字段<br />
4.查询中与其它表关联的字段,字段常常建立了外键关系<br />
5.查询中排序的字段<br />
6.查询中统计或分组统计的字段</p>
<p>三.什么情况下应不建或少建索引<br />
1.表的记录很少<br />
2.对一些经常处理的业务表应在查询允许的情况下尽量减少索引<br />
3.数据重复且分布平均的表字段<br />
假如一个表有10万行记录，有一个字段A只有T和F两种值，且每个值的分布概率大约为50%，那么对这种表A字段建索引一般不会提高数据库的查询速度</p>
<p>四.索引应用注意事项<br />
1. IS NULL 与 IS NOT NULL <br />
不能用null作索引，任何包含null值的列都将不会被包含在索引中。即使索引有多列这样的情况下，只要这些列中有一列含有null，该列就会从索引中排除。也就是说如果某列存在空值，即使对该列建索引也不会提高性能。 任何在where子句中使用is null或is not null的语句优化器是不允许使用索引的。</p>
<p>2.带通配符（%）的like语句 <br />
如： select * from building where name like '%中心%'<br />
name为building表的索引，则此索引就不会生效，这里由于通配符（%）在搜寻词首出现，通配符如此使用会降低查询速度。然而当通配符出现在字符串其他位置时，优化器就能利用索引<br />
select * from building where name like '&amp;中心%'</p>
<p>3. Order by语句 <br />
　　ORDER BY语句决定了如何将返回的查询结果排序,任何在Order by语句的非索引项或者有计算表达式都将降低查询速度。order by后面的排序字段尽量使用索引字段。</p>
<p>4.'&lt;&gt;'的用法<br />
例如：<br />
select * from building where id&lt;&gt;5000;<br />
select * from building where id&gt;5000 or id&lt;5000<br />
结果一样，但是第二句id索引生效。</p>
<p>5.可以使用外部连接优化not in子句，例如：<br />
select name from building where fk_building in (select deptid from test where name='test' and ifdeleted=0);<br />
　　<br />
改为：<br />
select name from building a,test b where a.fk_building=b.id and b.name='test' and ifdeleted=0;</p>
<p>6.索引列是否函数的参数。如是，索引在查询时用不上。</p>
<p>7.主从表关联方式<br />
如果：building.id上有一索引<br />
在district.id上有索引<br />
如：<br />
select contract_code from building a,district b where a.id=b.id<br />
building.id上的索引就会生效<br />
反之同理。</p>
<p><br />
8.是否存在潜在的数据类型转换。如将字符型数据与数值型数据比较，ORACLE会自动将字符型用to_number()函数进行转换，从而导致上一种现象的发生。</p>
<p><br />
9.索引应用的优先级；</p>
<p>(1).唯一性索引的等级高于非唯一性索引. 这个规则只有当WHERE子句中索引列和常量比较才有效.如果索引列和其他表的索引类相比较. 这种子句在优化器中的等级是非常低的.</p>
<p>(2).如果多个索引在一个查询中都可应用，那么如果条件中应用索引和常量进行比较，那么这个索引先被利用。</p>
<p><br />
10.语句的执行计划中有不良索引时，可以人为地屏蔽该索引，方法：<br />
　　<br />
　　。数值型：在索引字段上加0，例如<br />
　　select * from building where id+0 = 0;<br />
　　<br />
　　。字符型：在索引字段上加&#8216;&#8217;，例如<br />
　　select * from building where name||&#8217;&#8217;='test';</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
  <img src ="http://www.blogjava.net/agun/aggbug/185384.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/agun/" target="_blank">agun</a> 2008-03-11 15:07 <a href="http://www.blogjava.net/agun/archive/2008/03/11/185384.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>postgre存储过程简单实用方法 （过程语言： PL/pgSQL）</title><link>http://www.blogjava.net/agun/archive/2008/03/06/184131.html</link><dc:creator>agun</dc:creator><author>agun</author><pubDate>Thu, 06 Mar 2008 01:12:00 GMT</pubDate><guid>http://www.blogjava.net/agun/archive/2008/03/06/184131.html</guid><wfw:comment>http://www.blogjava.net/agun/comments/184131.html</wfw:comment><comments>http://www.blogjava.net/agun/archive/2008/03/06/184131.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/agun/comments/commentRss/184131.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/agun/services/trackbacks/184131.html</trackback:ping><description><![CDATA[<p>postgre存储过程简单实用方法 （过程语言： PL/pgSQL）</p>
<p>一，介绍常用的PL/pgSQL结构和语法：<br />
1，结构 <br />
PL/pgSQL是一种块结构的语言，比较方便的是用pgAdmin III新建Function，填入一些参数就可以了。基本上是这样的：<br />
CREATE OR REPLACE FUNCTION 函数名(参数1，[整型 int4, 整型数组 _int4, &#8230;])<br />
RETURNS 返回值类型 AS<br />
$BODY$<br />
DECLARE<br />
变量声明<br />
BEGIN<br />
函数体<br />
END;<br />
$BODY$<br />
LANGUAGE &#8216;plpgsql&#8217; VOLATILE; </p>
<p>2，变量类型 除了postgresql内置的变量类型外，常用的还有 RECORD ，表示一条记录。<br />
赋值 ：&#8220;变量 := 表达式;&#8221;<br />
连接字符串的是&#8220;||&#8221;，比如 sql := &#8216;SELECT * FROM&#8217; || table || &#8216;WHERE &#8230;&#8217;;<br />
3，判断 <br />
IF 条件 THEN<br />
&#8230;<br />
ELSEIF 条件 THEN<br />
&#8230;<br />
ELSE<br />
&#8230;<br />
END IF;<br />
4，循环 循环有好几种写法：<br />
WHILE expression LOOP<br />
statements<br />
END LOOP;<br />
还有常用的一种是：（从1循环到9可以写成FOR i IN 1..9 LOOP）<br />
FOR name IN [ REVERSE ] expression .. expression LOOP<br />
statements<br />
END LOOP;</p>
<p>二 跟mysql对比较</p>
<p><br />
1，postgre 中的limit不支持LIMIT #,# 这样的语法。</p>
<p>而是支持 LIMIT and OFFSET clauses 语法</p>
<p>mysql上面的两种方式都支持。<br />
2，存储过程中在ibatis中的使用：</p>
<p>(1)，mysql存储过程可以直接返回结果集，同时可以有out参数<br />
例如：<br />
存储过程：<br />
CREATE&nbsp; PROCEDURE `test`<br />
(IN _login VARCHAR(32), <br />
IN _psw VARCHAR(32), <br />
OUT _ret INTEGER(10),<br />
&nbsp;OUT _id INTEGER(10), <br />
OUT _name VARCHAR(32), <br />
OUT _email VARCHAR(32), <br />
OUT _phone VARCHAR(20), <br />
OUT _active INTEGER(11))//同时返回多个结果集合 </p>
<p>BEGIN<br />
&nbsp;&nbsp;&nbsp; DECLARE CONTINUE HANDLER FOR NOT FOUND set _ret =-1;<br />
&nbsp;&nbsp;&nbsp; set _ret = 0 ;</p>
<p>&nbsp;&nbsp;&nbsp; select id,name,email,phone,active<br />
&nbsp;&nbsp;&nbsp; into _id,_name,_email,_phone,_active<br />
&nbsp;&nbsp;&nbsp; from test<br />
&nbsp;&nbsp;&nbsp; where tx_account.`loginname`=_login and tx_account.`password`=MD5(_psw) and active=1;<br />
&nbsp;&nbsp;&nbsp; ---------返回结果集-----<br />
&nbsp;&nbsp;&nbsp; if _ret = 0 then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select a.id as id ,a.name as name,a.priority as priority<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from test b left join test1 a on b.role=a.id<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where b.account=_id;<br />
&nbsp;&nbsp;&nbsp; end if;<br />
END;<br />
直接返回结果集<br />
ibatis文件<br />
&nbsp; &lt;parameterMap id="testParameterMap" class="params"&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;parameter property="loginname" jdbcType="VARCHAR" javaType="java.lang.String" mode="IN"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;parameter property="password" jdbcType="VARCHAR" javaType="java.lang.String" mode="IN"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;parameter property="ret" jdbcType="INTEGER" javaType="java.lang.Integer" mode="OUT"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;parameter property="id" jdbcType="INTEGER" javaType="java.lang.Integer" mode="OUT"/&gt;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; &lt;parameter property="name" jdbcType="VARCHAR" javaType="java.lang.String" mode="OUT"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;parameter property="phone" jdbcType="VARCHAR" javaType="java.lang.String" mode="OUT"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;parameter property="email" jdbcType="VARCHAR" javaType="java.lang.String" mode="OUT"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;parameter property="active" jdbcType="INTEGER" javaType="java.lang.Integer" mode="OUT"/&gt;<br />
&nbsp; &lt;/parameterMap&gt;<br />
&nbsp; <br />
&nbsp; &lt;procedure id="test" parameterMap="testMap" resultMap="AccountRoleResultMap"&gt;<br />
&nbsp;&nbsp;&nbsp; {call test(?,?,?,?,?,?,?,?)}<br />
&nbsp; &lt;/procedure&gt;&nbsp;<br />
&nbsp;&nbsp; <br />
dao 的实现<br />
定义一个传参的map params ,</p>
<p>&nbsp;&nbsp;HashMap&lt;String,Object&gt; params = new HashMap&lt;String,Object&gt;();<br />
&nbsp;&nbsp;//把需要的参数放到map中<br />
&nbsp;&nbsp;params.put("id",account.getId());<br />
&nbsp;&nbsp;params.put("ret",null);<br />
&nbsp;&nbsp;params.put("loginname", null);<br />
&nbsp;&nbsp;params.put("name", null);<br />
&nbsp;&nbsp;params.put("email", null);<br />
&nbsp;&nbsp;params.put("phone",null);<br />
&nbsp;&nbsp;params.put("active", null);<br />
&nbsp;&nbsp;定义一个list <br />
&nbsp;&nbsp;List list=null;<br />
&nbsp;&nbsp;&nbsp;list= (List)(getSqlMapClientTemplate().queryForList("test",params));<br />
&nbsp;&nbsp;//上面这样操作就可以获得存储过程返回的结果集。&nbsp;<br />
&nbsp;&nbsp;&nbsp;Object var; <br />
&nbsp;&nbsp;&nbsp;var = params.get("ret");//从map 中获得制定的输出参数的值。<br />
在mysql中不需要的ibatis的配置文件中，声明返回的结果集。<br />
(2) postgre的函数返回结果集<br />
在postgre中返回结果集一定要在ibatis中定义输出参数。<br />
&nbsp; 方法1：不能输出参数，使用直接返游标的方法<br />
例如：<br />
函数：<br />
CREATE OR REPLACE FUNCTION test(IN _login VARCHAR(32))//只有输入参数<br />
&nbsp; RETURNS <br />
&nbsp; refcursor //制定返回类型为游标。<br />
&nbsp; AS<br />
$BODY$<br />
declare video_cur refcursor;<br />
BEGIN</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; open video_cur for<br />
&nbsp;select id , title from test;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return video_cur ;//返回游标<br />
END<br />
$BODY$<br />
&nbsp; LANGUAGE 'plpgsql' VOLATILE;<br />
ALTER FUNCTION test(integer) OWNER TO postgres;<br />
ibatis文件</p>
<p>&nbsp;&nbsp;&nbsp; &lt;parameterMap id="testParameters" class="java.util.HashMap"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;parameter property="result" jdbcType="OTHER" javaType="java.sql.ResultSet" mode="OUT"/&gt;//返回结果集<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;parameter property="loginName" jdbcType="VARCHAR" javaType="java.lang.String" mode="IN"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;parameter property="loginPasswd" jdbcType="VARCHAR" javaType="java.lang.String" mode="IN"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/parameterMap&gt;<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; &lt;procedure id="test" resultMap="testResultMap" parameterMap="testParameters" &gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {? = call test(?,?)}<br />
&nbsp;&nbsp;&nbsp; &lt;/procedure&gt;<br />
&nbsp;&nbsp;&nbsp; <br />
上面的map文件描述了3个参数,按照调用方式: ? = call test(?, ?)的顺序，<br />
第一个参数是返回结果集的，这里的jdbcType填写OTHER，javaType填写java.sql.ResultSet，<br />
如果是ORACLE的存储过程通过游标返回结果集的话，jdbcType应该填写为ORACLECURSOR，<br />
不过在PostgreSQL中不能用ORACLECURSOR，得用OTHER。</p>
<p>dao的实现： <br />
定义map文件 parameters ；<br />
&nbsp;List list;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HashMap&lt;String, String&gt; parameters = new HashMap&lt;String, String&gt;();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parameters.put("loginName", loginName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parameters.put("loginPasswd", loginPasswd);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list=getSqlMapClientTemplate().queryForList("test", parameters);//这样来得到返回的结果集。<br />
&nbsp;return list;<br />
方法2： 同时返回多个结果，</p>
<p>函数：<br />
CREATE OR REPLACE FUNCTION test(IN _login VARCHAR(32), <br />
IN _psw VARCHAR(32), <br />
OUT _ret INTEGER,<br />
&nbsp;OUT _id INTEGER, <br />
OUT _name VARCHAR(32), <br />
OUT _email VARCHAR(32), <br />
OUT _phone VARCHAR(20), <br />
OUT _ref refcursor ---返回一个游标<br />
)<br />
&nbsp; RETURNS record <br />
&nbsp; AS<br />
$BODY$<br />
declare video_cur refcursor;<br />
BEGIN<br />
&nbsp;&nbsp;&nbsp; select id,name,email,phone<br />
&nbsp;&nbsp;&nbsp; into _id,_name,_email,_phone<br />
&nbsp;&nbsp;&nbsp; from test<br />
&nbsp;&nbsp;&nbsp; where tx_account.`loginname`=_login and tx_account.`password`=MD5(_psw) and active=1;</p>
<p>&nbsp;&nbsp;&nbsp; open _ref&nbsp; for<br />
&nbsp;&nbsp;&nbsp; select id , title from test1;<br />
END<br />
$BODY$<br />
&nbsp; LANGUAGE 'plpgsql' VOLATILE;<br />
ALTER FUNCTION test(integer) OWNER TO postgres;</p>
<p>如果返回多个结果集，就要使用返回伪类型 record可以在输出参数中指定游标为其中一个out参数<br />
ibatis文件</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out 参数输出游标<br />
&nbsp;&lt;parameterMap id="ParameterMap" class="map" &gt;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; &lt;parameter property="login " jdbcType="VARCHAR" javaType="java.lang.String" mode="IN"/&gt;&nbsp;<br />
&nbsp;&nbsp;&nbsp; &lt;parameter property="password" jdbcType="VARCHAR" javaType="java.lang.String" mode="IN"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;parameter property="ret" jdbcType="INTEGER" javaType="java.lang.Integer" mode="OUT"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;parameter property="id" jdbcType="INTEGER" javaType="java.lang.Integer" mode="OUT"/&gt;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; &lt;parameter property="name" jdbcType="VARCHAR" javaType="java.lang.String" mode="OUT"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;parameter property="phone" jdbcType="VARCHAR" javaType="java.lang.String" mode="OUT"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;parameter property="email" jdbcType="VARCHAR" javaType="java.lang.String" mode="OUT"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;parameter property="ref" jdbcType="OTHER" javaType="java.sql.ResultSet" mode="OUT"/&gt;&nbsp; //返回结果集&nbsp; &nbsp;&nbsp; </p>
<p>&nbsp; &nbsp;&lt;/parameterMap&gt;</p>
<p>&nbsp;&lt;procedure id="test" parameterMap="ParameterMap" resultMap="ResultMap"&gt;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp; &nbsp;{call test(?,?,?,?,?,?,?,?)}&nbsp; <br />
&nbsp; &nbsp;&lt;/procedure&gt;</p>
<p>dao的实现跟方法1 相同&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;</p>
<p>&nbsp;</p>
 <img src ="http://www.blogjava.net/agun/aggbug/184131.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/agun/" target="_blank">agun</a> 2008-03-06 09:12 <a href="http://www.blogjava.net/agun/archive/2008/03/06/184131.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>