如何使用Sphinx搜索大型JOINed表?

时间:2011-12-10 21:15:46

标签: database search full-text-search sphinx denormalization

我的数据库中有几个不同的表,我试图使用Sphinx进行快速全文搜索。为了便于讨论,让我们说感兴趣的主要记录是装箱单,其中一个包含在订单发货时。如何在不完全非规范化数据库的情况下使用Sphinx在所有这些表中执行复杂查询?

每个装箱单都列出了装运中包含的每个包装箱的订单号,发货人,收件人和跟踪号。单独的表包含有关订单商品的信息。附加表包含客户地址信息。因此,订单包含框和框包含项目。 (此问题底部列出的示例模式)。

我希望能够向Sphinx查询以下问题的答案:

  • 有多少人住在一条名为" Maple"订购了一个带有" large"在描述中?
  • 包含哪些订单包含" blue"在框说明或订单项目中。描述

要回答这些类型的问题,我需要参考几个表格。由于Sphinx没有JOIN,因此一种选择是对数据库进行非规范化。使用视图进行非规范化,以便每行代表一个订单项 - 加上它的父框和订单的所有数据,将导致数十亿个非常宽的行。所以我一直在为每个表创建一个单独的索引。但这并不允许我像SQL JOIN那样跨表查询。还有其他解决方案吗?

示例数据库

CREATE TABLE orders (
    id               integer PRIMARY KEY,
    date_ordered     date,
    customer_po      varchar
);
INSERT INTO orders VALUES (1, '2012-12-13', NULL);
INSERT INTO orders VALUES (2, '2012-12-14', 'DF312442');

CREATE TABLE parties (
    id               integer PRIMARY KEY,
    order_id         integer NOT NULL REFERENCES orders(id),
    party_type       varchar,
    company          varchar,
    city             varchar,
    state            char(2)
);
INSERT INTO parties VALUES (1, 1, 'shipper', 'ACME, Inc.', 'New York', 'NY');
INSERT INTO parties VALUES (2, 1, 'recipient', 'Wylie Coyote Corp.', 'Flagstaff', 'AZ');
INSERT INTO parties VALUES (3, 2, 'shipper', 'Cyberdyne', 'Las Vegas', 'NV');
-- Please disregard the fact that this design permits multiple shippers and multiple recipients
-- per order.  This is a vastly simplified version of the system I'm working on.

CREATE TABLE boxes (
    id               integer PRIMARY KEY,
    order_id         integer NOT NULL REFERENCES orders(id),
    tracking_num     varchar NOT NULL,
    description      varchar NOT NULL,
);
INSERT INTO boxes VALUES (1, 1, '1234567890', 'household goods');
INSERT INTO boxes VALUES (2, 1, '0987654321', 'kitchen appliances');
INSERT INTO boxes VALUES (3, 2, 'ABCDE12345', 'audio equipment');

CREATE TABLE box_contents (
    id               integer PRIMARY KEY,
    order_id         integer NOT NULL REFERENCES orders(id),
    box              integer NOT NULL REFERENCES boxes(id),
    qty_units        integer,
    description      varchar
);
INSERT INTO box_contents VALUES (1, 1, 1, 4, 'cookbook');
INSERT INTO box_contents VALUES (2, 1, 1, 2, 'baby bottle');
INSERT INTO box_contents VALUES (3, 1, 2, 1, 'television');
INSERT INTO box_contents VALUES (4, 2, 3, 2, 'lamp');

1 个答案:

答案 0 :(得分:4)

将JOIN放在构建索引的sql_query中。表保持规范化,但在构建索引时进行非规范化。

它只是一个基本的例子,但你的查询会像.. ..

sql_query = SELECT o.id,customer_po,UNIX_TIMESTAMP(date_ordered) AS date_ordered,   \
    GROUP_CONCAT(DISTINCT party_type) AS party_type, \
    GROUP_CONCAT(DISTINCT company) AS company, \
    GROUP_CONCAT(DISTINCT city) AS city, \
    GROUP_CONCAT(DISTINCT description) AS description \
  FROM orders o \
    INNER JOIN parties p ON (o.id = p.order_id) \
    INNER JOIN box_contents b ON (o.id = b.order_id) \
  GROUP BY o.id \
  ORDER BY NULL

更新:或者可以使用sql_joined_field来做同样的事情但避免实际的sql_query连接。然后Sphinx为您做加入过程