Symfony2 / Doctrine2:不要在模式上删除全文索引:更新

Posted

技术标签:

【中文标题】Symfony2 / Doctrine2:不要在模式上删除全文索引:更新【英文标题】:Symfony2 / Doctrine2: Don't drop fulltext index on schema:update 【发布时间】:2013-11-09 22:01:29 【问题描述】:

为了在 Symfony2 中支持全文索引,我使用了 MyISAM 镜像表。我们会定期将生产数据集复制到该表中,并创建一个 SearchEntity 来映射表的结构并与真实实体相关联。因此,我们可以在 SearchRepository 上执行搜索查询(使用自定义 MATCH AGAINST 语句构建器)并通过解析关联来检索找到的实体。

现在,当我执行 doctrine:schema:updateDoctrine2 时,它无法识别该表上的(手动添加的)索引并想要删除它们。不幸的是,没有建议注释说“但保持这个索引不变!”。

我已经尝试使用@Index 注释来欺骗 Doctrine,其字段与全文索引(前缀 ft_)中的字段相同,然后手动执行一些 SQL 以用我的 FT 索引替换它们,但同样失败:当 Doctrine 最初使用那些虚拟索引创建表失败,因为索引键长度大于 1000 字节(这是 mysql 中明显原因的硬限制)

问题是:我可以建议 Doctrine 将它在表中找到的索引原封不动地保留在 schema:update 命令上吗?有没有办法将其破解到框架中?每次模式更新后重新创建全文索引非常麻烦:(

搜索实体:

/**
 * @ORM\Table(name="tmp_search2",options="engine"="MyISAM",
 *            uniqueConstraints=@ORM\UniqueConstraint(name="uq",columns="language_id","product_offer_id","product_group_id","retailer_id" ),
  *            indexes=@Index(name="price_idx", columns="product_offer_price"),
  *                     @Index(name="started_at_idx", columns="product_offer_started_at"),
  *                     @Index(name="ended_at_idx", columns="product_offer_ended_at"),
  *                     @Index(name="ft_products", columns="product_name"),
  *                     @Index(name="ft_product_group", columns="product_group_name"),
  *                     @Index(name="ft_product_retailer", columns="retailer_name")
  *            
  * )
  * @ORM\Entity(repositoryClass="SearchRepository")
  */

class SearchEntity

    /**
     * This field is only here to satisfy doctrine's need for a non-composite primary key.
     * @ORM\Id
     * @ORM\Column(name="id", type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
     private $searchId;

   /**
    * @ORM\ManyToOne(targetEntity="ProductOffer")
    * @ORM\JoinColumn(name="product_offer_id", referencedColumnName="id")
    */
    private $productOffer;

   /**
     * @var integer
     *
     * @ORM\Column(name="product_offer_price", type="integer")
     */
    private $price;

创建 tmp_search 索引的 SQL(首先删除学说留下的内容,然后创建我们的)

DROP INDEX ft_products ON tmp_search2;
DROP INDEX ft_product_group ON tmp_search2;
DROP INDEX ft_product_retailer ON tmp_search2;

# import product data and then...

CREATE FULLTEXT INDEX ft_products ON tmp_search2 (product_name,product_short_text,product_long_text);
CREATE FULLTEXT INDEX ft_product_group ON tmp_search2 (product_group_name);
CREATE FULLTEXT INDEX ft_product_retailer ON tmp_search2 (retailer_name);

【问题讨论】:

这不是直接的解决方案,但您可以创建自己的控制台命令,该命令在内部执行 doctrine:schema:update,然后运行您的自定义 SQL 以创建附加索引 所以我永远不会再执行教义:模式:更新自身?不,我认为它属于框架并且在那里很好(每个人都知道它应该如何工作:如果它说,一切都很好,一切都很好)。我认为 Doctrine 方面需要做一些工作来真正解决这个问题。但也许有一些方法可以扩展 Doctrine 的类型(最好使用包),以便正确识别全文索引 在 Doctrine 2.5 中有一个“标志”选项。设置为“全文”,它将能够自动创建 ft 索引:***.com/questions/23448266/… 【参考方案1】:

我能够使用迁移解决此问题,然后添加具有相同名称的虚假索引。

迁移使用原始 SQL 添加了实际全文索引:

$this->addSql('ALTER TABLE content ADD FULLTEXT fulltext_content(title, description)');

然后我将索引添加到实体定义中:

@ORM\Table(name="content", indexes=@ORM\Index(name="fulltext_content",columns="title","description"))

只要你先生成全文索引,Doctrine 就不会再删除它们了。

【讨论】:

这实际上是在不久前开始工作的(我不知道,什么时候)。现在也在用这个。【参考方案2】:

就像其他人回答的那样,在生产环境中使用 doctrine:schema:update 不是一个好主意,因为代码中的任何小错误都可能导致一半的数据库被丢弃。

我在一个相当大的项目上工作,我们使用doctrine:schema:update --dump-sql 来查找需要执行的查询并手动执行它们。

编辑:我另外唯一的建议是,如果您不想手动执行查询,您可以处理 doctrine:schema:update --dump-sql 的输出,过滤您不想执行的查询并在数据库。或者创建一个在更新架构后创建索引的命令,例如myproject:schema:createIndexes(或其他)

【讨论】:

【参考方案3】:
    不应在生产环境中使用学说:模式:更新。请改用迁移。 我记得 Doctrine 2 没有完全支持 MyIsam,但您可以手动创建表并使用它 Mysql 全文搜索不是搜索的最佳选择。也许 Sphinx 或 Lucene 更适合您的任务?

【讨论】:

1.我们正处于一个大型迁移过程中,并且每天都迁移我们的数据 -> 它可能会发生很大变化,因此无论如何我们都必须导入大部分数据,因此重新创建数据库不是问题。 2. Doctrine 只允许你注释一个实体的表来使用 MyISAM。该表是自动生成的,但明显缺少的外键会刺激命令。 3. 当然可以,但是只要您的管理团队不愿意支持它,您就必须使用您所拥有的 :)

以上是关于Symfony2 / Doctrine2:不要在模式上删除全文索引:更新的主要内容,如果未能解决你的问题,请参考以下文章

在 Doctrine2/Symfony2 中的重复条目上插入忽略

如何在 Doctrine2 (Symfony2) 中按案例排序

Symfony2 项目中的 Doctrine2 映射问题

Doctrine2 自定义类型不像主键 Symfony2 那样工作

带有 Symfony2 的 Doctrine2 无法识别数据库字符集和排序规则

Symfony2 和 Doctrine2 :用两个实体填充表单(一个复杂的场景)