Tìm các từ không ngừng được sử dụng phổ biến nhất trong một cột


7

Nói một cách đơn giản, tôi có một cột Postgres chứa văn xuôi thông thường và muốn xác định các từ xđược sử dụng phổ biến nhất ("từ" là một nhóm các ký tự được phân cách bởi một khoảng trắng, nhưng không phải là từ dừng) trên tất cả các hàng.

Tôi đã tìm thấy hai giải pháp gần như đạt được mục đích:

SELECT *                                       
FROM   ts_stat($$SELECT to_tsvector('english', title) FROM item$$) 
ORDER  BY ndoc DESC
LIMIT  50;

Điều này là tuyệt vời, ngoại trừ nó trả lại từ gốc.

SELECT   UNNEST(string_to_array(title, ' ')) AS word, COUNT(*) AS ct
FROM     item 
GROUP    BY 1 
ORDER    BY 2 DESC
LIMIT    50;

Điều này trả về các từ đầy đủ, nhưng bao gồm các từ dừng.

Vì mục đích đơn giản: các từ dừng được cho là được tìm thấy trên TABLE stop_words (lowercase_stopword text PRIMARY KEY).

Bất cứ ai có thể giúp tôi qua dòng?

Câu trả lời:


4

Truy vấn đầu tiên của bạn khá gần. Để loại bỏ các gốc không mong muốn, tạo một cấu hình tìm kiếm văn bản với một từ điển đơn giản không làm điều đó.

Tôi đề nghị sử dụng một lược đồ riêng cho các đối tượng tìm kiếm văn bản, nhưng đó hoàn toàn là tùy chọn:

CREATE SCHEMA ts;
GRANT USAGE ON SCHEMA ts TO public;
COMMENT ON SCHEMA ts IS 'text search objects';

CREATE TEXT SEARCH DICTIONARY ts.english_simple_dict (
    TEMPLATE = pg_catalog.simple
  , STOPWORDS = english
);

CREATE TEXT SEARCH CONFIGURATION ts.english_simple (COPY = simple);
ALTER  TEXT SEARCH CONFIGURATION ts.english_simple
   ALTER MAPPING FOR asciiword WITH ts.english_simple_dict;  -- 1, 'Word, all ASCII'

Sau đó, truy vấn của bạn cũng hoạt động và rất nhanh:

SELECT *                                       
FROM   ts_stat($$SELECT to_tsvector('ts.english_simple', title) FROM item$$) 
ORDER  BY ndoc DESC
LIMIT  50;

dbfiddle ở đây

Điều này hoạt động với các từ viết thường mà không xuất phát và không ngắt cho các chữ cái không phải ASCII.

Backgroud

Đọc chương Từ điển đơn giản trong hướng dẫn.

Định nghĩa chính xác của một "từ" là một vấn đề khó khăn. Trình phân tích cú pháp tìm kiếm văn bản mặc định (hiện tại là duy nhất) xác định 23 loại mã thông báo khác nhau. Xem:

SELECT * FROM ts_token_type('default');

Các cấu hình tìm kiếm văn bản tích hợp ánh xạ hầu hết các từ điển (tích hợp). Ánh xạ cho englishcấu hình:

SELECT tt.*, m.mapdict::regdictionary AS dictionary
FROM   pg_ts_config_map m
LEFT   JOIN   ts_token_type(3722) tt ON tt.tokid = m.maptokentype
WHERE  mapcfg = 'english'::regconfig  --  'ts.english_simple'::regconfig
ORDER  BY tt.tokid;

Bản demo ở trên tạo ra một cấu hình mới dựa trên simplecấu hình và vì tất cả các từ dừng tiếng Anh thuộc loại 'asciiword', chúng tôi chỉ cần ánh xạ loại này để loại bỏ các từ dừng, không xuất phát hoặc bất cứ thứ gì khác.


1

Điều này sẽ cung cấp cho bạn đầu ra dự kiến ​​của bạn:

-- Some example data
WITH titles(title) AS
(
   VALUES 
      ('This is a title'), 
      ('This is another title'), 
      ('This is finally a third title'), 
      ('and I don''t like Mondays')
)

-- List here all the words that you consider 'stop words'
-- in lowercase
, stop_words(word) AS
(

    VALUES ('the'), ('a'), ('and')
)

-- Make list of (lowercased) found words
, found_lower_words AS
(
SELECT 
    lower(unnest(string_to_array(title, ' '))) AS word
FROM
    titles
)

-- And now anti-join with the stop_words, group and count
SELECT
    word, count(*) AS word_count
FROM
    found_lower_words
    LEFT JOIN stop_words USING(word)
WHERE
    stop_words.word is NULL
GROUP BY
    word
ORDER BY
    word_count DESC, word ASC
LIMIT
    50 ;

Kết quả sẽ là:

  |---------+---|
  |   is    | 3 |
  |---------+---|
  |  this   | 3 |
  |---------+---|
  |  title  | 3 |
  |---------+---|
  | another | 1 |
  |---------+---|
  |  don't  | 1 |
  |---------+---|
  | finally | 1 |
  |---------+---|
  |    i    | 1 |
  |---------+---|
  |  like   | 1 |
  |---------+---|
  | mondays | 1 |
  |---------+---|
  |  third  | 1 |
  |---------+---|

1

Câu trả lời của Erwin là tốt hơn

Theo dữ liệu mẫu từ @joanolo ở trên , tôi muốn trả lời theo cách không yêu cầu bạn liệt kê rõ ràng các từ dừng. Làm như vậy đòi hỏi các giả định về từ điển.

WITH titles(title) AS
(
   VALUES 
      ('This is a title'), 
      ('This is another title'), 
      ('This is finally a third title'), 
      ('and I don''t like Mondays')
)
SELECT token, count(*)
FROM titles
CROSS JOIN LATERAL ts_debug(title)
WHERE alias = 'asciiword'
        AND array_length(lexemes,1) <> 0
GROUP BY token;

  token  | count 
---------+-------
 title   |     3
 another |     1
 like    |     1
 third   |     1
 Mondays |     1
 finally |     1
(6 rows)

Chúng tôi đang sử dụng array_lengthđể khắc phục một lỗi nội bộ được mô tả ở đây


ts_debug()rất tốn kém vì nó thực hiện rất nhiều công việc chúng ta không cần cho truy vấn. Thêm vào đó, điều này sẽ thất bại đối với các ký tự không phải ASCII. Và có lẽ chúng tôi cũng không muốn nó nhạy cảm. Trên thực tế, tất cả những gì chúng ta cần là một cấu hình tìm kiếm văn bản không xuất phát. Tôi đã thêm một giải pháp khác.
Erwin Brandstetter
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.