手机网站 英文,一周新闻热点事件,企业邮箱注册申请免费注册入口,100人公司局域网搭建Elasticsearch 与 PostgreSQL 集成#xff1a;让关系型数据库的搜索“飞”起来关键词#xff1a;Elasticsearch, PostgreSQL, 搜索增强, 数据同步, CDC, 倒排索引, 全文检索
摘要#xff1a;PostgreSQL是关系型数据库的“瑞士军刀”#xff0c;擅长事务、复杂查询和数据一致…Elasticsearch 与 PostgreSQL 集成让关系型数据库的搜索“飞”起来关键词Elasticsearch, PostgreSQL, 搜索增强, 数据同步, CDC, 倒排索引, 全文检索摘要PostgreSQL是关系型数据库的“瑞士军刀”擅长事务、复杂查询和数据一致性但全文搜索、实时分析能力却像“钝刀割肉”Elasticsearch是搜索领域的“闪电侠”擅长全文检索、分词、实时聚合但不适合做事务处理。本文将用“仓库导购员”的生活比喻拆解两者集成的核心逻辑——如何用PostgreSQL存“准确的数据”用Elasticsearch做“快速的搜索”用同步机制保证“数据一致”。通过实战案例、数学模型和场景分析帮你掌握从0到1的集成方案解决关系型数据库的搜索痛点。背景介绍为什么要让两个“高手”合作1.1 你可能遇到的搜索痛点假设你是一家网上书店的开发者用PostgreSQL存了10万本图书数据书名、作者、简介存在text字段价格、库存、分类存在numeric/int字段用户搜索“Python入门”时你用LIKE %Python入门%查询——结果要么慢得让用户骂娘全表扫描要么漏结果比如用户输入“入门Python”或“Python 入门”想做“按出版社统计Python书籍数量”的聚合查询PostgreSQL要扫描全表延迟高达几秒想给搜索结果加“关键词高亮”PostgreSQL的tsvector功能根本搞不定。这时候你会发现PostgreSQL的搜索能力根本配不上它的“关系型数据库天花板”地位。1.2 两个“高手”的互补优势我们需要一个“搜索专家”来补PostgreSQL的短板——Elasticsearch简称ESES是“倒排索引”的天生玩家能在1秒内处理百万级数据的全文搜索支持中文分词比如IK分词器能把“Python入门”拆成“Python”“入门”不管用户输入顺序如何都能命中能实时做聚合分析比如统计出版社分布、高亮关键词、自动补全但ES有个致命缺点不适合做事务处理——如果你用ES存库存并发下单时可能出现“超卖”因为ES的更新不是原子操作。所以最佳组合是PostgreSQL做“事实来源”存需要事务保证的数据比如库存、价格ES做“搜索层”存需要快速查询的文本数据比如书名、简介两者通过同步机制保持数据一致。1.3 预期读者与文档结构预期读者用PostgreSQL但受困于搜索的开发者、想了解ES与关系型数据库集成的工程师文档结构从“生活比喻”讲核心概念→用“数学模型”讲搜索原理→用“实战案例”讲集成步骤→用“场景分析”讲落地价值。1.4 术语表术语通俗解释倒排索引像字典的“索引页”按关键词找文档比如“Python”对应所有包含它的书籍CDCChange Data Capture像仓库的“摄像头”记录PostgreSQL的每一次数据变动插入/更新/删除同步机制像“搬运工”把PostgreSQL的变动数据传给ES保持两者一致映射Mapping像“翻译器”定义PostgreSQL字段如何对应ES的字段类型比如text→ES的text类型用IK分词核心概念用“书店故事”讲清楚集成逻辑2.1 故事引入书店的“搜索困境”你开了一家线下书店仓库PostgreSQL所有书籍的“准确信息”都存在这里——每本书的库存、价格、进货渠道都记在仓库的账本上导购员ES负责接待顾客记住每本书的“关键信息”书名、作者、简介的关键词搬运工同步工具每天把仓库的新书、改价书、卖完的书的信息告诉导购员顾客用户想找“Python入门”的书直接问导购员ES搜索导购员快速说出有哪些书然后带顾客去仓库取货PostgreSQL查详细信息。这个故事里每个角色的职责完美对应集成中的组件——理解了这个故事你就理解了集成的核心逻辑2.2 核心概念拆解像给小学生讲“书店分工”我们把集成中的3个核心概念用“书店角色”重新解释概念1PostgreSQL——“准确的仓库”PostgreSQL是“事实的唯一来源”Single Source of Truth负责存储需要事务保证的数据比如库存减库存必须是原子操作不能多减或漏减处理复杂关系查询比如“查询2023年出版的、价格低于50元的Python书籍”保持数据的强一致性比如修改价格后所有查询都能看到最新值。比喻仓库的账本是唯一准确的——不管导购员怎么说最终要以仓库的账本为准。概念2Elasticsearch——“聪明的导购员”ES是“搜索与分析的引擎”负责存储需要快速查询的文本数据书名、作者、简介用倒排索引快速匹配关键词比如“Python入门”→找到所有包含这两个词的书籍做实时分析比如“统计最近7天最受欢迎的Python书籍”提供用户友好的搜索功能关键词高亮、自动补全、拼写纠错。比喻导购员不需要记住每本书的库存但要记住每本书的“卖点”——这样才能快速回答顾客的问题。概念3同步机制——“靠谱的搬运工”同步机制是连接PostgreSQL和ES的“桥梁”负责捕获PostgreSQL的数据变动插入/更新/删除将变动数据转换成ES能理解的格式比如PostgreSQL的timestamp→ES的date类型将变动数据同步到ES保证两者数据一致。比喻搬运工每天从仓库拿“变动清单”比如今天进了5本《Python入门》卖了3本《Java编程》然后告诉导购员更新自己的“记忆”。2.3 核心概念的关系像“书店协作流程”三个概念的协作流程就像顾客找书的过程顾客提问用户搜索“有没有Python入门的书”导购员回答ES搜索快速找出所有包含“Python”和“入门”的书籍ID仓库取货PostgreSQL查询用书籍ID从仓库查最新的价格、库存结果展示返回给用户把书名、作者、价格、库存展示给用户。总结PostgreSQL是“后台”ES是“前台”同步机制是“纽带”——前台负责快速响应后台负责数据准确。2.4 核心架构的文本示意图与Mermaid流程图文本示意图用户 → 后端服务 → ES搜索书籍ID → PostgreSQL查详细信息 → 后端服务 → 用户 ▲ ▲ | | | 同步机制搬运工 | 事实来源仓库 |__________________________| PostgreSQL的变动Mermaid流程图捕获变动同步数据用户后端服务ElasticsearchPostgreSQL同步机制核心原理为什么ES能“快速搜索”3.1 倒排索引导购员的“记忆方式”ES的核心优势是倒排索引Inverted Index——这是它能快速搜索的“秘密武器”。什么是倒排索引我们先看正排索引像书的“目录页”按“书号”找“内容”比如书号1→《Python入门》书号2→《Java编程》。而倒排索引像书的“索引页”按“关键词”找“书号”比如“Python”→书号1、书号3“入门”→书号1、书号4。比喻正排索引是“按学号找学生”倒排索引是“按特长找学生”比如“会Python”→学生A、学生B。倒排索引的结构倒排索引由两部分组成词项词典Term Dictionary所有关键词的列表比如“Python”、“入门”、“Java”** postings list postings 列表**每个关键词对应的文档ID列表比如“Python”→[1,3]表示文档1和3包含“Python”。示例假设我们有3本书书号书名1《Python从入门到精通》2《Java编程快速上手》3《Python核心编程》倒排索引的结构词项词典Python、入门、精通、Java、编程、快速、上手、核心postings列表Python → [1,3]入门 → [1]精通 → [1]Java → [2]编程 → [2,3]快速 → [2]上手 → [2]核心 → [3]当用户搜索“Python编程”时ES会找到“Python”对应的文档[1,3]找到“编程”对应的文档[2,3]取交集→文档3《Python核心编程》按相关性排序比如文档1同时包含“Python”和“编程”吗如果包含排序更靠前。3.2 TF-IDF导购员的“相关性判断”ES怎么判断“哪本书最符合用户的查询”答案是TF-IDF词项频率-逆文档频率——这是衡量“关键词在文档中重要性”的数学模型。TF-IDF的公式TF-IDF由两部分组成TFTerm Frequency词项频率关键词在文档中出现的次数 / 文档总词数比如“Python”在文档1中出现3次文档1总词数100→TF3/1000.03IDFInverse Document Frequency逆文档频率log(总文档数 / 包含该关键词的文档数)比如总文档数1000包含“Python”的文档有100→IDFlog(1000/100)1。最终的TF-IDF值TF × IDF比如上面的例子→0.03×10.03。为什么TF-IDF有效TF关键词在文档中出现次数越多说明文档越相关比如“Python”出现5次的文档比出现1次的更相关IDF关键词在所有文档中出现的次数越少说明关键词越“独特”比如“Python”比“的”更独特因为“的”几乎所有文档都有。示例用户搜索“Python入门”我们有3本书书号书名TF(Python)TF(入门)IDF(Python)IDF(入门)TF-IDF总和1《Python从入门到精通》0.050.0310.69890.05×1 0.03×0.6989 0.07092《Java入门经典》00.0410.69890 0.04×0.6989 0.02793《Python核心编程》0.04010.69890.04×1 0 0.04结果排序书10.0709书30.04书20.0279——这完全符合用户的预期3.3 同步机制搬运工的“工作方式”同步机制是集成的“核心难点”——如何保证PostgreSQL的变动能及时、准确地同步到ES同步的两种方式方式原理适用场景优点缺点定时同步Pull每隔一段时间查询PostgreSQL的变动数据比如用updated_at last_sync_time同步到ES数据变动不频繁、对延迟要求不高实现简单延迟高比如10分钟同步一次、可能漏数据CDCPush捕获PostgreSQL的WAL日志Write-Ahead Log预写日志实时同步变动数据数据变动频繁、对延迟要求高实时性好、无漏数据实现复杂、需要设置PostgreSQL的wal_level结论CDC是生产环境的首选——因为它能实时同步且不会漏数据。CDC的工作原理PostgreSQL的WAL日志是“所有数据变动的记录”——每次插入、更新、删除数据都会先写WAL日志再修改数据。CDC工具比如Debezium会连接PostgreSQL订阅WAL日志解析WAL日志提取变动数据比如插入的行、更新前的值、更新后的值转换数据格式比如PostgreSQL的timestamp→ES的date类型同步到ES比如插入→ES新增文档更新→ES修改文档删除→ES删除文档。比喻CDC就像仓库的“摄像头”——每本书的变动都被拍下来搬运工根据录像内容告诉导购员更新记忆。项目实战从0到1搭建集成环境4.1 开发环境准备我们用Docker快速搭建环境避免本地安装的麻烦PostgreSQL版本15开启logical wal_levelElasticsearch版本8.11.1单节点Kibana版本8.11.1用于ES的可视化Debezium Server版本2.3用于CDC同步。步骤1创建Docker网络dockernetwork create elastic# 创建名为elastic的网络让容器之间可以通信步骤2启动PostgreSQLdockerrun--namepostgres\--netelastic\-ePOSTGRES_USERpostgres\-ePOSTGRES_PASSWORDpostgres\-ePOSTGRES_DBbookstore\-p5432:5432\-dpostgres:15关键配置开启logical wal_levelCDC需要进入PostgreSQL容器dockerexec-itpostgresbash修改postgresql.confvi/var/lib/postgresql/data/postgresql.conf找到wal_level改成logicalwal_level logical # 开启逻辑日志保存退出重启PostgreSQLdockerrestart postgres步骤3启动Elasticsearch和Kibana# 启动Elasticsearchdockerrun--nameelasticsearch\--netelastic\-p9200:9200\-p9300:9300\-ediscovery.typesingle-node\-ddocker.elastic.co/elasticsearch/elasticsearch:8.11.1# 启动Kibanadockerrun--namekibana\--netelastic\-p5601:5601\-eELASTICSEARCH_HOSTShttp://elasticsearch:9200\-ddocker.elastic.co/kibana/kibana:8.11.1获取Elasticsearch密码dockerexec-itelasticsearch bin/elasticsearch-reset-password-uelastic# 重置elastic用户的密码访问Kibana打开浏览器→http://localhost:5601→用elastic用户和密码登录。步骤4启动Debezium ServerDebezium是开源的CDC工具支持PostgreSQL、MySQL等数据库。我们用Debezium Server直接同步到ES。创建Debezium配置目录mkdir-pdebezium/data# 用于存储Debezium的偏移量记录同步到哪条日志了创建debezium/application.properties配置文件# 源端PostgreSQL配置 debezium.source.connector.classio.debezium.connector.postgresql.PostgresConnector debezium.source.offset.storage.file.filenamedata/offsets.dat # 偏移量存储文件 debezium.source.offset.flush.interval.ms60000 # 每60秒刷新偏移量 debezium.source.database.hostnamepostgres # PostgreSQL的Docker容器名 debezium.source.database.port5432 debezium.source.database.userpostgres debezium.source.database.passwordpostgres debezium.source.database.dbnamebookstore debezium.source.database.server.namepostgres # 服务器名称唯一标识 debezium.source.schema.include.listpublic # 同步public schema下的表 debezium.source.table.include.listpublic.books # 同步books表 debezium.source.plugin.namepgoutput # PostgreSQL的逻辑解码插件 # Sink端Elasticsearch配置 debezium.sink.typeelasticsearch debezium.sink.elasticsearch.cluster.namedocker-cluster # ES集群名称默认是docker-cluster debezium.sink.elasticsearch.hostshttp://elasticsearch:9200 # ES的地址 debezium.sink.elasticsearch.usernameelastic # ES的用户名 debezium.sink.elasticsearch.password你的Elasticsearch密码 # 替换成步骤3获取的密码 debezium.sink.elasticsearch.index.prefixbooks # ES索引前缀最终索引名是books_public_books debezium.sink.elasticsearch.document.id.fieldid # 用PostgreSQL的id作为ES文档的ID保证幂等性启动Debezium Serverdockerrun--namedebezium\--netelastic\-v$(pwd)/debezium:/debezium/data\-ddebezium/server:2.34.2 创建PostgreSQL表与测试数据连接PostgreSQLdockerexec-itpostgres psql-Upostgres-dbookstore创建books表CREATETABLEbooks(idSERIALPRIMARYKEY,# 主键titleVARCHAR(255)NOTNULL,# 书名authorVARCHAR(100)NOTNULL,# 作者descriptionTEXT,# 简介priceNUMERIC(10,2)NOTNULL,# 价格stockINTNOTNULLDEFAULT0,# 库存created_atTIMESTAMPDEFAULTCURRENT_TIMESTAMP# 创建时间);插入测试数据INSERTINTObooks(title,author,description,price,stock)VALUES(Python从入门到精通,张三,一本适合新手的Python教程,49.90,100),(Java编程快速上手,李四,Java开发的入门指南,59.90,50),(Python核心编程,王五,深入讲解Python的核心原理,79.90,30);4.3 配置ES索引映射ES默认的映射可能不适合中文分词比如把“Python从入门到精通”拆成“python”、“从”、“入门”、“到”、“精通”所以我们需要手动创建索引映射使用IK分词器ES的中文分词插件。安装IK分词器dockerexec-itelasticsearch bin/elasticsearch-plugininstallhttps://github.com/medcl/elasticsearch-analysis-ik/releases/download/v8.11.1/elasticsearch-analysis-ik-8.11.1.zipdockerrestart elasticsearch# 重启ES生效在Kibana中创建索引映射打开Kibana→Dev Tools→输入以下请求PUT/books_public_books # 索引名对应Debezium的index.prefixschematable{mappings:{properties:{title:{type:text,analyzer:ik_max_word,# 索引时用最细粒度分词search_analyzer:ik_smart# 搜索时用最粗粒度分词},author:{type:text,analyzer:ik_max_word},description:{type:text,analyzer:ik_max_word},price:{type:float},stock:{type:integer},created_at:{type:date}}}}点击“运行”→看到{acknowledged: true}说明成功。4.4 验证同步效果在PostgreSQL中插入一条数据INSERTINTObooks(title,author,description,price,stock)VALUES(Python入门指南,赵六,零基础学Python,39.90,80);在Kibana中查询ES索引打开Kibana→Dev Tools→输入以下请求GET/books_public_books/_search{query:{match_all:{}# 查询所有文档}}你会看到ES中已经同步了4条文档包括刚插入的《Python入门指南》。4.5 测试搜索功能我们测试“Python入门”的搜索看看ES的表现在Kibana中输入以下请求POST/books_public_books/_search{query:{match:{title:Python入门# 搜索书名包含“Python入门”的文档}},highlight:{fields:{title:{}# 高亮书名中的关键词}}}查看结果ES会返回《Python从入门到精通》、《Python入门指南》、《Python核心编程》按TF-IDF排序书名中的“Python”和“入门”会被em标签高亮比如emPython/em从em入门/em到精通。实际应用场景集成能解决哪些问题5.1 场景1电商商品搜索PostgreSQL存什么商品的SKU、价格、库存、分类、商家信息需要事务保证比如库存减少必须原子操作ES存什么商品的名称、描述、标签、品牌需要快速搜索和过滤流程用户搜索“无线耳机降噪”→ES返回商品ID→PostgreSQL查价格、库存→展示给用户价值既保证了搜索速度ES的倒排索引又保证了数据准确PostgreSQL的事务。5.2 场景2博客系统全文搜索PostgreSQL存什么博客的作者、发布时间、分类、评论数需要事务保证比如评论数增加ES存什么博客的标题、内容、标签需要全文搜索和高亮流程用户搜索“Elasticsearch 集成”→ES返回博客ID→PostgreSQL查作者、发布时间→展示给用户价值解决了PostgreSQLLIKE查询慢的问题同时支持关键词高亮。5.3 场景3企业文档管理PostgreSQL存什么文档的上传者、上传时间、权限需要权限控制比如只有管理员能删除ES存什么文档的标题、内容、关键词需要快速搜索和聚合流程用户搜索“2023年预算报告”→ES返回文档ID→PostgreSQL查权限→展示给用户价值让企业员工快速找到需要的文档提高工作效率。工具与资源推荐让集成更轻松6.1 同步工具Debezium开源CDC工具支持PostgreSQL、MySQL、MongoDB等适合实时同步LogstashElastic Stack的一部分适合定时同步比如每10分钟同步一次Airbyte云原生数据集成平台支持低代码配置同步任务。6.2 可视化工具KibanaES的官方可视化工具用于调试ES查询、查看索引状态pgAdminPostgreSQL的官方管理工具用于创建表、插入数据Elasticsearch-head浏览器插件用于查看ES的索引和文档。6.3 学习资源Debezium官方文档https://debezium.io/documentation/详细讲解CDC的配置Elasticsearch官方指南https://www.elastic.co/guide/en/elasticsearch/reference/current/index.htmlES的核心原理和APIPostgreSQL全文搜索文档https://www.postgresql.org/docs/current/textsearch.htmlPostgreSQL的内置搜索功能书籍《Elasticsearch实战》讲解ES的实际应用、《PostgreSQL实战》讲解PostgreSQL的高级特性。未来发展趋势集成的“下一站”7.1 向量搜索从“关键词”到“语义”传统的全文搜索是“关键词匹配”而向量搜索是“语义匹配”——比如用户搜索“找一本像《人类简史》的书”向量搜索能理解“人类简史”的语义比如“人类历史”、“文明发展”然后找到语义相似的书。PostgreSQL通过pgvector扩展支持向量存储ES通过dense_vector类型支持向量索引集成价值实现“语义搜索”让搜索结果更符合用户意图。7.2 实时同步优化从“秒级”到“毫秒级”随着业务对实时性的要求越来越高同步延迟将从“秒级”降到“毫秒级”——比如Debezium 2.0支持“增量快照”不需要全量同步直接同步增量数据ES 8.0支持“异步搜索”处理大规模数据的实时搜索。7.3 云原生集成从“自建”到“托管”越来越多的企业选择云托管服务比如AWS RDS PostgreSQL托管的PostgreSQL服务支持logical wal_levelElastic Cloud托管的ES服务支持自动扩容、备份价值不需要自己管理服务器降低运维成本。总结你学到了什么8.1 核心概念回顾PostgreSQL关系型数据库的“仓库”负责存储需要事务保证的数据Elasticsearch搜索领域的“导购员”负责快速处理全文搜索和分析同步机制连接两者的“搬运工”负责实时同步数据倒排索引ES快速搜索的“秘密武器”按关键词找文档TF-IDFES判断相关性的“数学模型”衡量关键词的重要性。8.2 集成的核心价值用PostgreSQL的“强一致性”解决数据准确问题用ES的“高搜索性能”解决用户体验问题——这是关系型数据库搜索增强的“最优解”。思考题动动小脑筋如果你有一个1000万条数据的PostgreSQL表要同步到ES初始同步很慢你有什么优化方法如果同步过程中出现“PostgreSQL改了数据但ES没改”的情况你怎么排查如何让ES的搜索结果更符合用户意图比如用户输入“Python入门”如何让《Python从入门到精通》排在《Python核心编程》前面附录常见问题与解答Q1同步延迟怎么办如果用CDC检查Debezium的offset.flush.interval.ms缩小刷新间隔比如从60秒改成10秒如果用Logstash缩短定时任务的间隔比如从10分钟改成1分钟。Q2数据不一致怎么办幂等性用PostgreSQL的主键作为ES文档的ID比如Debezium的document.id.fieldid这样重复同步不会产生重复数据全量同步定期做全量同步比如每天凌晨同步一次覆盖ES中的旧数据。Q3ES索引映射错误怎么办手动创建映射在同步前手动创建ES索引的映射比如设置title字段用IK分词器用Debezium转换器修改Debezium的配置转换字段类型比如把PostgreSQL的numeric→ES的float。扩展阅读 参考资料Debezium官方文档https://debezium.io/documentation/Elasticsearch官方指南https://www.elastic.co/guide/en/elasticsearch/reference/current/index.htmlPostgreSQL全文搜索文档https://www.postgresql.org/docs/current/textsearch.html《Elasticsearch实战》作者拉梅什·瓦姆西·坎塔姆拉《PostgreSQL实战》作者尹正杰写在最后Elasticsearch与PostgreSQL的集成不是“替代”而是“互补”——就像书店的仓库和导购员缺一不可。希望这篇文章能帮你解决关系型数据库的搜索痛点让你的应用“搜索更快、数据更准”