2017-09-22 12 views
1

テキストブロック内のすべての単語の文字の%を検索するための条件を作成します。私はregexp_matchesが私の必要とするかもしれないと思っていますが、各単語/フレーズの%オカレンスを探すためにそれをコーディングする方法がわかりません。例えばテキストブロック内の単語/句内の文字のパーセンテージを検索

(select count(*) from regexp_matches(table.blocktext, ' ', 'gi') 

テキストの各ブロックできます。私は、テキストのブロック全体の中にスペースを特定して、ブロックの長さにわたってそのため%を計算するには、以下の本を使用していた過去に

たとえば、100〜1000文字(1つまたは2つ)です。そして、それらの文字の中で、例えば、すべての単語について、同じ文字が80%以上出現しているとします(文字、数字など)。だから、私はそれを言葉だけではなく、80%以上の単語/フレーズを構成する任意の文字を言っている。私はまた、これが一般的であるかもしれない短い言葉を避けるように、長さ条件を追加しなければならないと思う(例えば、「woohoo」など)。だから多分8以上の長さの条件。

私は今までの検索で例を見つけることはできませんでしたが、Postgresでこれが可能であることを期待しています。どんな援助も大変ありがとうと思います。これを行うには

+0

私は、これは正規表現でさえ可能だとは思いません。実用的ではありません。しかし、短時間の研究の後では、[フルテキスト検索](https://www.postgresql.org/docs/9.5/static/textsearch-controls.html#TEXTSEARCH-RANKING)でこれを行うことができるようです。 )? –

+0

Tom、ありがとう、私は下のErwinの助けを借りて作業するバージョンを手に入れましたが、それは決して速くないでしょう。私は完全なテキスト検索を使用したことがないので、次にそれについて学びます。フィードバックを投稿していただき、ありがとうございます。 – afropunk

答えて

2

一つの方法:

SELECT c, count(*) AS ct, (count(*) * 100)/length($1) AS pct 
FROM unnest(string_to_array($1, NULL)) c 
WHERE length($1) > 7 -- maybe a length condition of 8 or more 
GROUP BY 1 
HAVING count(*) > (length($1) * 80)/100 -- 80 is your % threshold 
ORDER BY 2 DESC; 

$1が分析される文字列であること。

与えられたテキストの80%以上を占める文字を返します。明らかにパーセンテージが50以上の場合は1行にすることはできません。文字が十分に頻繁に使用されていない場合は何もしません。

(count(*) * 100)/length($1)は、整数除算で丸めて計算する最も簡単な方法です。正確な結果が必要な場合は、代わりにcount(*) >= (length($1) * 80)/100.0を使用してください(ここでも>=を書き留めてください)。 (100.0は計算結果をnumericと厳密に一致させる)

これを関数または準備文に簡単にラップし、文字列とパーセントをパラメータとして渡すことができます。

CREATE OR REPLACE FUNCTION f_char_pct(_word text, _pct int) 
    RETURNS boolean AS 
$func$ 
SELECT EXISTS (
    SELECT 1 
    FROM unnest(string_to_array(_word, NULL)) c 
    GROUP BY c 
    HAVING count(*) > (length(_word) * _pct)/100 
    ) 
$func$ LANGUAGE sql IMMUTABLE; 

コール:

「与えられた文書内の単一の単語が7つの以上の文字と所定のしきい値以下の文字の割合で存在する場合、falseを返すエルスtrue

ので、同様
SELECT NOT EXISTS (
    SELECT 1 
    FROM unnest(string_to_array('1000000000000z abc 1234567890', ' ')) word 
    WHERE length(word) > 7 
    AND NOT f_char_pct(word, 80) 
    ); 

返信falseです。
'abc'は無視され、他の2つの単語は同じ文字の> 80%を持つため、true '1000000000000z abc 2222222'が返されます。
NULL入力btwの場合はfalseを返します。あなたはまた、単一の関数で全体を包むことができhere

dbfiddle

...

unnest(string_to_array($1, ' '))分割ワードすべてのスペースに。より洗練された定義が可能です。テキスト検索インフラストラクチャを使用できます。この等価で..

select count(*) from regexp_matches(table.blocktext, ' ', 'gi') 

が、はるかに速く1:私はあなたの簡単なカウントに代わる、ところで


を:考えてみましょう

SELECT length(table.blocktext) - length(replace(table.blocktext, ' ', '')) 

正規表現関数は強力ですが、価格がかかります。そして集約ステップはそれをはるかに高価にします。関連:

+0

ありがとうございました。私は、 'FROM unnest(string_to_array($ 1、NULL))c'を動作させるいくつかの問題を抱えていましたが、コードを少し修正してCTEスタイルを使用し、 。ネストされていない(string_to_array())キーは間違いなくキーであったので、それを提供してくれてありがとうございました。同様に、より高速な 'SELECT length(table.blocktext) - length(replace(table.blocktext、' '、' '))を提供するためのkよりも。私はこれをいくつかの関連するクエリでもうまく使ってしまいました... – afropunk

+0

私は本当に関数のラッピングをまだ検討していませんが、その情報を提供してくれてありがとう、ここには私が確かに慣れている私の知識を築く。出力が良いので、これを解決済みとしてマークします。処理時間に役立つAWSで書き直したいと思っています。アイデアがある場合は、すぐに別の質問を投稿します。しかし、もう一度、本当に非常にあなたの完全かつ詳細な答えに感謝していただきありがとうございます。 – afropunk

関連する問題