
2æ28æ¥ã«ãç§ãã¡ã®ãªãã£ã¹ã§éå¬ãããSphinxSearch-meetupã§ãã¬ãŒã³ããŒã·ã§ã³ãè¡ããŸããã 圌ã¯ããã«ããã¹ãæ€çŽ¢ã®ããã«ã€ã³ããã¯ã¹ãå®æçã«åæ§ç¯ããã³ãŒãå
ã®æŽæ°ããã€ã³ãã¬ãŒã¹ãã§ã¬ãŒã«ã¿ã€ã ã€ã³ããã¯ã¹ã«éä¿¡ããã€ã³ããã¯ã¹ãšMariaDBããŒã¿ããŒã¹ã®ç¶æ
ãèªååæããæ¹æ³ã«ã€ããŠè©±ããŸããã ç§ã®ã¬ããŒãã®ãããªé²ç»ã¯ãªã³ã¯ããå
¥æã§ããŸãããããªãèŠããããèªãããšã奜ã人ã®ããã«ãç§ã¯ãã®èšäºãæžããŸããã
ãããããæ€çŽ¢ãã©ã®ããã«ã¢ã¬ã³ãžããããããããŠãªãç§ãã¡å
šå¡ããããå§ãããã
ç§ãã¡ã®æ€çŽ¢ã¯ãå®å
šã«æšæºçãªã¹ããŒã ã«åŸã£ãŠç·šæãããŸããã
ããã³ããšã³ãããããŠãŒã¶ãŒãªã¯ãšã¹ãã¯PHPã§èšè¿°ãããã¢ããªã±ãŒã·ã§ã³ãµãŒããŒã«éããã次ã«åœŒã¯ããŒã¿ããŒã¹ãšéä¿¡ããŸãïŒMariaDBããããŸãïŒã æ€çŽ¢ãè¡ãå¿
èŠãããå Žåãã¢ããªã±ãŒã·ã§ã³ãµãŒããŒã¯ãã©ã³ãµãŒïŒhaproxyããããŸãïŒãåŒã³åºããŸããããã¯ãsearchdãå®è¡ãããŠãããµãŒããŒã®1ã€ã«æ¥ç¶ãããã®ãµãŒããŒã¯æ¢ã«æ€çŽ¢ãå®è¡ããŠçµæãè¿ããŸãã
ããŒã¿ããŒã¹ããã®ããŒã¿ã¯éåžžã«äŒçµ±çãªæ¹æ³ã§ã€ã³ããã¯ã¹ã«åé¡ãããŸããã¹ã±ãžã¥ãŒã«ã«åŸã£ãŠãæ¯èŒçæè¿æŽæ°ãããããã¥ã¡ã³ãã§æ°åããšã«ã€ã³ããã¯ã¹ãåæ§ç¯ãããããããã¢ãŒã«ã€ããããã¥ã¡ã³ãã§ã€ã³ããã¯ã¹ãåæ§ç¯ããŸããé·ãéäœãèµ·ãããŸããã§ããïŒã ã€ã³ããã¯ã¹äœæçšã«å²ãåœãŠããããã·ã³ãããã€ããããŸããã¹ã¯ãªããã¯ã¹ã±ãžã¥ãŒã«ã«åŸã£ãŠå®è¡ãããæåã«ã€ã³ããã¯ã¹ãäœæãã次ã«ç¹å¥ãªæ¹æ³ã§ã€ã³ããã¯ã¹ãã¡ã€ã«ã®ååãå€æŽããŠãããå¥ã®ãã©ã«ããŒã«é
眮ããŸãã ãŸããsearchdã䜿çšããåãµãŒããŒã§ã¯ãrsyncã1åã«1åèµ·åããããã®ãã©ã«ããŒãããã¡ã€ã«ãsearchdã€ã³ããã¯ã¹ãã©ã«ããŒã«ã³ããŒããŸãããã®åŸãäœããã³ããŒãããå ŽåãRELOAD INDEXãªã¯ãšã¹ããå®è¡ããŸãã
ãã ããåéãšç©ºåžã®äžéšã®å€æŽã§ã¯ãã§ããã ãæ©ãã€ã³ããã¯ã¹ã«ãå°éãããå¿
èŠããããŸããã ããšãã°ããããªãã¯ãã¡ã€ã³ã«é
眮ãããæ¬ å¡ããããªã±ãŒã·ã§ã³ããåé€ãããå ŽåããŠãŒã¶ãŒã®èŠ³ç¹ãããæ°ç§ä»¥å
ã«åé¡ããæ¶ããããšãæåŸ
ããã®ã劥åœã§ãã ãã®ããããã®çš®ã®å€æŽã¯UPDATEã¯ãšãªã䜿çšããŠsearchdã«çŽæ¥éä¿¡ãããŸãã ãããŠããããã®å€æŽããã¹ãŠã®ãµãŒããŒäžã®ã€ã³ããã¯ã¹ã®ãã¹ãŠã®ã³ããŒã«é©çšãããããã«ãåã€ã³ããã¯ã¹ã«åæ£ã€ã³ããã¯ã¹ãèšå®ããããã¹ãŠã®æ€çŽ¢ãããã€ã³ã¹ã¿ã³ã¹ã«å±æ§ã®æŽæ°ãéä¿¡ãããŸãã ã¢ããªã±ãŒã·ã§ã³ãµãŒããŒã¯åŒãç¶ããã©ã³ãµãŒã«æ¥ç¶ããåæ£ã€ã³ããã¯ã¹ãæŽæ°ãã1ã€ã®ãªã¯ãšã¹ããéä¿¡ããŸãã ãããã£ãŠãsearchdã䜿çšãããµãŒããŒã®ãªã¹ããäºåã«ç¥ãå¿
èŠããæ£ç¢ºã«searchdã䜿çšãããµãŒããŒã«å°éããå¿
èŠããããŸããã
ãããã¯ãã¹ãŠããŸããããŸããããåé¡ããããŸããã
- ããã¥ã¡ã³ãã®äœæïŒããã¯ç§ãã¡ã«ãšã£ãŠå±¥æŽæžãŸãã¯æ¬ å¡ã§ãïŒãšã€ã³ããã¯ã¹ãžã®ãšã³ããªéã®å¹³åé
延ã¯ãããŒã¿ããŒã¹å
ã®ãããã®æ°ã«æ£æ¯äŸããŸããã
- åæ£ã€ã³ããã¯ã¹ã䜿çšããŠå±æ§ã®æŽæ°ãéä¿¡ããããããããã®æŽæ°ãã€ã³ããã¯ã¹ã®ãã¹ãŠã®ã³ããŒã«é©çšãããä¿èšŒã¯ãããŸããã§ããã
- ã€ã³ããã¯ã¹ã®åæ§ç¯äžã«çºçãããç·æ¥ãã®å€æŽã¯ã
RELOAD INDEX
ã³ãã³ãã®å®è¡æã«å€±ããïŒåã«æ°ããäœæãããã€ã³ããã¯ã¹ã«ãªãããïŒã次ã®ã€ã³ããã¯ã¹åäœæåŸã«ã®ã¿ã€ã³ããã¯ã¹ã«åæ ãããŸãã 
- searchdã䜿çšããŠãµãŒããŒäžã®ã€ã³ããã¯ã¹ãæŽæ°ããããã®ã¹ã¯ãªããã¯ãäºãã«ç¬ç«ããŠå®è¡ããããããã®éã®åæã¯ãããŸããã§ããã ãã®ãããç°ãªããµãŒããŒã§ã€ã³ããã¯ã¹ãæŽæ°ããéã®é
延ã¯æ°åã«éããå¯èœæ§ããããŸãã
- æ€çŽ¢ã«é¢é£ããäœãããã¹ãããå¿
èŠãããå Žåã¯ãå€æŽã®ãã³ã«ã€ã³ããã¯ã¹ãåæ§ç¯ããå¿
èŠããããŸããã
ãããã®åé¡ã®ããããã¯ãæ€çŽ¢ã€ã³ãã©ã¹ãã©ã¯ãã£ãæ ¹æ¬çã«äœãçŽã䟡å€ã¯ãããŸããã§ãããããããããŸãšãããšãããªãç®ã«èŠããŠäººçãå°ç¡ãã«ããŸããã
ãªã¢ã«ã¿ã€ã Sphinxã€ã³ããã¯ã¹ã䜿çšããŠãäžèšã®åé¡ã«å¯ŸåŠããããšã«ããŸããã ããã«ãRTã€ã³ããã¯ã¹ãžã®ç§»è¡ã ãã§ã¯äžååã§ããã ããŒã¿ç«¶åãå®å
šã«åãé€ãã«ã¯ãã¢ããªã±ãŒã·ã§ã³ããã€ã³ããã¯ã¹ãžã®ãã¹ãŠã®æŽæ°ãåããã£ãã«ãçµç±ããããã«ããå¿
èŠããããŸããã ããã«ãã€ã³ããã¯ã¹ã®åæ§ç¯äžã«ããŒã¿ããŒã¹ã«å ããããå€æŽãã©ããã«ä¿åããå¿
èŠããããŸããïŒçµå±ãã€ã³ããã¯ã¹ãåæ§ç¯ããªããã°ãªããªãããšããããŸãããæé ã¯ç¬æã§ã¯ãããŸããïŒã
ããŒã¿è»¢éãã£ãã«ãªã©ã®MySQLã¬ããªã±ãŒã·ã§ã³ãããã³ã«ã䜿çšããŠæ¥ç¶ããããšã«ããŸãããMySQLbinlogã¯ãã€ã³ããã¯ã¹ã®åæ§ç¯äžã«å€æŽãä¿åããå Žæã§ãã ãã®ãœãªã¥ãŒã·ã§ã³ã«ãããã¢ããªã±ãŒã·ã§ã³ã³ãŒãããSphinxã«æžã蟌ãå¿
èŠããªããªããŸããã ãŸããã°ããŒãã«ãã©ã³ã¶ã¯ã·ã§ã³IDã§è¡ããŒã¹ã®ã¬ããªã±ãŒã·ã§ã³ãæ¢ã«äœ¿çšããŠãããããããŒã¿ããŒã¹ã¬ããªã«ã®åãæ¿ãã¯éåžžã«ç°¡åã«è¡ããŸãã
ãã¡ãããããããã€ã³ããã¯ã¹ã«éä¿¡ããããã®å€æŽãååŸããããã«ããŒã¿ããŒã¹ã«çŽæ¥æ¥ç¶ãããšããèãã¯æ°ãããã®ã§ã¯ãããŸããïŒ2016幎ã«ãAvitoã®ååããã¬ãŒã³ããŒã·ã§ã³ãè¡ãã Sphinxã®ããŒã¿ãã¡ã€ã³ããŒã¿ããŒã¹ãšåæããåé¡ãã©ã®ããã«è§£æ±ºãããã詳ãã説æããŸããã PostgreSQLã§ã¯ãªãMariaDBãããã³å€ãSphinxãã©ã³ãïŒã€ãŸããããŒãžã§ã³2.3.2ïŒãç°ãªãç¹ãé€ãã圌ãã®çµéšã掻çšããŠåæ§ã®ã·ã¹ãã ãèªåãã¡ã§äœæããããšã«ããŸããã
MariaDBã®å€æŽããµãã¹ã¯ã©ã€ãããSphinxã®ã€ã³ããã¯ã¹ãæŽæ°ãããµãŒãã¹ãäœæããŸããã 圌ã®è²¬ä»»ã¯æ¬¡ã®ãšããã§ãã
- ã¬ããªã±ãŒã·ã§ã³ãããã³ã«ãä»ããŠMariaDBãµãŒããŒã«æ¥ç¶ããbinlogããã€ãã³ããåä¿¡ããŸãã
- çŸåšã®ãã€ããªãã°ã®äœçœ®ãšæåŸã«å®äºãããã©ã³ã¶ã¯ã·ã§ã³ã®çªå·ã远跡ããŸãã
- binlogã€ãã³ãã®ãã£ã«ã¿ãªã³ã°ã
- ã€ã³ããã¯ã¹ã§è¿œå ãåé€ããŸãã¯æŽæ°ããå¿
èŠãããããã¥ã¡ã³ããããã³æŽæ°ãããããã¥ã¡ã³ãã«ã€ããŠç¢ºèªãã-ã©ã®ãã£ãŒã«ããæŽæ°ããå¿
èŠãããã
- MariaDBããã®æ¬ èœããŒã¿ã®èŠæ±ã
- ã€ã³ããã¯ã¹æŽæ°ãªã¯ãšã¹ãã®çæãšå®è¡ã
- å¿
èŠã«å¿ããŠã€ã³ããã¯ã¹ãåæ§ç¯ããŸãã
go-mysqlã©ã€ãã©ãªã䜿çšããŠãã¬ããªã±ãŒã·ã§ã³ãããã³ã«ã䜿çšããŠæ¥ç¶ã確ç«ããŸããã 圌女ã¯MariaDBãšã®æ¥ç¶ã確ç«ããè€è£œã€ãã³ããèªã¿åãããããããã³ãã©ãŒã«æž¡ã責任ããããŸãã ãã®ãã³ãã©ãŒã¯ãã©ã€ãã©ãªã«ãã£ãŠå¶åŸ¡ãããgorutinã§å§ãŸããŸããããã³ãã©ãŒã³ãŒãã¯ç¬èªã«èšè¿°ããŸãã ãã³ãã©ãŒã³ãŒãã§ã¯ãã€ãã³ããèå³ã®ããããŒãã«ã®ãªã¹ãã§æ€èšŒããããããã®ããŒãã«ãžã®å€æŽãåŠçã®ããã«éä¿¡ãããŸãã ãã³ãã©ãŒã¯ãã©ã³ã¶ã¯ã·ã§ã³ã¹ããŒã¿ã¹ãä¿åããŸãã ããã¯ãã¬ããªã±ãŒã·ã§ã³ãããã³ã«ã®ã€ãã³ããé çªã«äžŠãã§ããããã§ããGTIDïŒãã©ã³ã¶ã¯ã·ã§ã³ã®éå§ïŒ-> ROWïŒããŒã¿ã®å€æŽïŒ-> XIDïŒãã©ã³ã¶ã¯ã·ã§ã³ã®çµäºïŒã§ãæåã®ãã©ã³ã¶ã¯ã·ã§ã³ã®ã¿ã«ãã©ã³ã¶ã¯ã·ã§ã³çªå·ã«é¢ããæ
å ±ãå«ãŸããŠããŸãã å€æŽãé©çšããããã€ããªãã°å
ã®äœçœ®ã«é¢ããæ
å ±ãä¿åããããã«ããã©ã³ã¶ã¯ã·ã§ã³çªå·ãå®äºãšãšãã«è»¢éããæ¹ã䟿å©ã§ãããã®ãããçŸåšã®ãã©ã³ã¶ã¯ã·ã§ã³ã®éå§ããå®äºãŸã§ã®çªå·ãèŠããŠããå¿
èŠããããŸãã
MySQL [(none)]> describe sync_state; +-----------------+--------+ | Field | Type | +-----------------+--------+ | id | bigint | | dummy_field | field | | binlog_position | uint | | binlog_name | string | | gtid | string | | flavor | string | +-----------------+--------+
searchdã䜿çšããŠãåãµãŒããŒäžã®1ã€ã®ããã¥ã¡ã³ãã®ç¹å¥ãªã€ã³ããã¯ã¹ã«æåŸã«å®äºãããã©ã³ã¶ã¯ã·ã§ã³ã®çªå·ãä¿åããŸãã ãµãŒãã¹ã®éå§æã«ãã€ã³ããã¯ã¹ãåæåãããäºæ³ãããæ§é ã«ãªã£ãŠããããšãããã³ãã¹ãŠã®ãµãŒããŒã«ä¿åãããäœçœ®ãååšãããã¹ãŠã®ãµãŒããŒã«åãã§ããããšã確èªããŸãã 次ã«ããããã®ãã§ãã¯ãæåããä¿åãããäœçœ®ãããã€ããªãã°ã®èªã¿åããéå§ã§ããå Žåãåææé ãéå§ããŸãã ãã§ãã¯ã«å€±æããå ŽåããŸãã¯ä¿åãããäœçœ®ãããã€ããªãã°ã®èªã¿åããéå§ã§ããªãã£ãå Žåãä¿åãããäœçœ®ãMariaDBãµãŒããŒã®çŸåšã®äœçœ®ã«ãªã»ããããã€ã³ããã¯ã¹ãåæ§ç¯ããŸãã
ã¬ããªã±ãŒã·ã§ã³ã€ãã³ãã®åŠçã¯ãããŒã¿ããŒã¹ã®ç¹å®ã®å€æŽã®åœ±é¿ãåããããã¥ã¡ã³ããç¹å®ããããšããå§ãŸããŸãã ãããè¡ãã«ã¯ããµãŒãã¹ã®æ§æã§ã察象ã®ããŒãã«ã®è¡å€æŽã€ãã³ãã®ã«ãŒãã£ã³ã°ãã€ãŸãããŒã¿ããŒã¹ã®å€æŽã®ã€ã³ããã¯ã¹ä»ãæ¹æ³ã決å®ããããã®äžé£ã®ã«ãŒã«ãªã©ãè¡ããŸããã
[[ingest]] table = "vacancy" id_field = "id" index = "vacancy" [ingest.column_map] user_id = ["user_id"] edited_at = ["date_edited"] profession = ["profession"] latitude = ["latitude_deg", "latitude_rad"] longitude = ["longitude_deg", "longitude_rad"] [[ingest]] table = "vacancy_language" id_field = "vacancy_id" index = "vacancy" [ingest.column_map] language_id = ["languages"] level = ["languages"] [[ingest]] table = "vacancy_metro_station" id_field = "vacancy_id" index = "vacancy" [ingest.column_map] metro_station_id = ["metro"]
ããšãã°ããã®ã«ãŒã«ã»ããã§ã¯ã vacancy
ã vacancy_language
ããã³vacancy_metro_station
ãžã®å€æŽã¯ã vacancy
ã€ã³ããã¯ã¹ã«å«ããå¿
èŠããããŸãã ææžçªå·ã¯ã vacancy
ããŒãã«ã®id
ãã£ãŒã«ããšãä»ã®2ã€ã®ããŒãã«ã®vacancy_id
ãã£ãŒã«ãã§vacancy_id
ãŸãã column_map
ãã£ãŒã«ãã¯ãç°ãªãããŒã¿ããŒã¹ããŒãã«ã®ãã£ãŒã«ãã«å¯Ÿããã€ã³ããã¯ã¹ãã£ãŒã«ãã®äŸåé¢ä¿ã®ããŒãã«ã§ãã
ããã«ãå€æŽã®åœ±é¿ãåããããã¥ã¡ã³ãã®ãªã¹ããåãåã£ãå Žåãããããã€ã³ããã¯ã¹ã§æŽæ°ããå¿
èŠããããŸãããããã«ã¯è¡ããŸããã ãŸããåããã¥ã¡ã³ãã®å€æŽãèç©ãããã®ããã¥ã¡ã³ãã®æåŸã®å€æŽããå°ãæéãçµéãããšïŒ100ããªç§ïŒããã«ã€ã³ããã¯ã¹ã«å€æŽãéä¿¡ããŸãã
å€ãã®å Žåãç°ãªãããŒãã«ã«åœ±é¿ãäžããããã€ãã®SQLã¯ãšãªã®å©ããåããŠããã¥ã¡ã³ããžã®åäžã®è«çå€æŽãçºçããæã«ã¯å®å
šã«ç°ãªããã©ã³ã¶ã¯ã·ã§ã³ã§å®è¡ããããããå€ãã®å Žåãäžå¿
èŠãªã€ã³ããã¯ã¹æŽæ°ãåé¿ããããã«ãããè¡ãããšã«ããŸããã
ç°¡åãªäŸãæããŸãã ãŠãŒã¶ãŒã空åžãç·šéãããšããŸãã å€æŽãä¿åããããã®ã³ãŒãã¯ãç°¡åã«ããããã«æ¬¡ã®ããã«èšè¿°ãããããšããããããŸãã
BEGIN; UPDATE vacancy SET edited_at = NOW() WHERE id = 123; DELETE FROM vacancy_language WHERE vacancy_id = 123; INSERT INTO vacancy_language (vacancy_id, language_id, level) VALUES (123, 1, "fluent"), (123, 2, "technical"); DELETE FROM vacancy_metro_station WHERE vacancy_id = 123; INSERT INTO vacancy_metro_station (vacancy_id, metro_station_id) VALUES (123, 55); ... COMMIT;
ã€ãŸããæåã«ãã¹ãŠã®å€ãã¬ã³ãŒãããªã³ã¯ããŒãã«ããåé€ããã次ã«æ°ããã¬ã³ãŒããæ¿å
¥ãããŸãã åæã«ãææžå
ã§äœãå€æŽãããŠããªããŠãããããã®åé€ããã³æ¿å
¥ã«é¢ãããšã³ããªããã€ããªãã°ã«æ®ã£ãŠããŸãã
å¿
èŠãªãã®ã ããæŽæ°ããããã«ã次ã®æäœãè¡ããŸãããå€æŽãããè¡ã䞊ã¹æ¿ããŠãåã€ã³ããã¯ã¹ãšããã¥ã¡ã³ãã®ãã¢ã«ã€ããŠããã¹ãŠã®å€æŽãæç³»åé ã«ååŸã§ããããã«ããŸããã ãã®åŸãããããé çªã«é©çšããŠãæçµçã«ã©ã®ããŒãã«ã®ã©ã®ãã£ãŒã«ããæçµçã«å€æŽãããã©ã®ãã£ãŒã«ããå€æŽãããŠããªãããå€æã§ããŸãããã®åŸã column_map
ããŒãã«column_map
䜿çšããŠã圱é¿ãåããããã¥ã¡ã³ãããšã«æŽæ°ããå¿
èŠããããã£ãŒã«ããšã€ã³ããã¯ã¹å±æ§ã®ãªã¹ãcolumn_map
ååŸã§ããŸãã ããã«ã1ã€ã®ããã¥ã¡ã³ãã«é¢é£ããã€ãã³ãã次ã
ã«å°çããããšã¯ãããŸããããç°ãªããã©ã³ã¶ã¯ã·ã§ã³ã§å®è¡ãããå Žåã¯ãç°ãªããããã«èŠããŸãã ããããã©ã®ããã¥ã¡ã³ããå€æŽãããããå€æããèœåã«ã€ããŠã¯ãããã¯åœ±é¿ããŸããã
åæã«ããã®ã¢ãããŒãã«ãããããã¹ããã£ãŒã«ãã«å€æŽããªããã°ãã€ã³ããã¯ã¹ã®å±æ§ã®ã¿ãæŽæ°ããSphinxãžã®å€æŽã®éä¿¡ãçµã¿åãããããšãã§ããŸããã
ãã®ãããã€ã³ããã¯ã¹ã§æŽæ°ããå¿
èŠãããããã¥ã¡ã³ããèŠã€ããããšãã§ããŸãã
å€ãã®å Žåãbinlogããã®ããŒã¿ã¯ã€ã³ããã¯ã¹ãæŽæ°ãããªã¯ãšã¹ããäœæããã®ã«ååã§ã¯ãªããããbinlogãèªã¿èŸŒãã åããµãŒããŒããæ¬ èœããŒã¿ãååŸããŸãã ãã®ããã«ããµãŒãã¹ã®èšå®ã§ããŒã¿ãåä¿¡ããããã®ãªã¯ãšã¹ããã³ãã¬ãŒãããããŸãã
[data_source.vacancy] # # - id parts = 4 query = """ SELECT vacancy.id AS `:id`, vacancy.profession AS `profession_text:field`, GROUP_CONCAT(DISTINCT vacancy_language.language_id) AS `languages:attr_multi`, GROUP_CONCAT(DISTINCT vacancy_metro_station.metro_station_id) AS `metro:attr_multi` FROM vacancy LEFT JOIN vacancy_language ON vacancy_language.vacancy_id = vacancy.id LEFT JOIN vacancy_metro_station ON vacancy_metro_station.vacancy_id = vacancy.id GROUP BY vacancy.id """
ãã®ãã³ãã¬ãŒãã§ã¯ããã¹ãŠã®ãã£ãŒã«ããç¹å¥ãªãšã€ãªã¢ã¹[___]:___
ããŒã¯ãããŠããŸãã
æ¬ èœããŒã¿ãåä¿¡ããèŠæ±ãçæãããšããšãã€ã³ããã¯ã¹ãæ§ç¯ãããšãã®äž¡æ¹ã§äœ¿çšãããŸãïŒããã«ã€ããŠã¯åŸã§èª¬æããŸãïŒã
ãã®ã¿ã€ãã®ãªã¯ãšã¹ããäœæããŸãïŒ
SELECT vacancy.id AS `id`, vacancy.profession AS `profession_text`, GROUP_CONCAT(DISTINCT vacancy_language.language_id) AS `languages`, GROUP_CONCAT(DISTINCT vacancy_metro_station.metro_station_id) AS `metro` FROM vacancy LEFT JOIN vacancy_language ON vacancy_language.vacancy_id = vacancy.id LEFT JOIN vacancy_metro_station ON vacancy_metro_station.vacancy_id = vacancy.id WHERE vacancy.id IN (< id , >) GROUP BY vacancy.id
次ã«ãåããã¥ã¡ã³ãã«ã€ããŠãããããã®ãªã¯ãšã¹ãã®çµæã§ãããã©ããã確èªããŸãã ããã§ãªãå Žåã¯ãã¡ã€ã³ããŒãã«ããåé€ãããããšãæå³ãããããã€ã³ããã¯ã¹ãããåé€ã§ããŸãïŒãã®ããã¥ã¡ã³ãã«å¯ŸããŠDELETE
ã¯ãšãªãå®è¡ããŸãïŒã ããå Žåã¯ããã®ããã¥ã¡ã³ãã®ããã¹ããã£ãŒã«ããæŽæ°ããå¿
èŠããããã©ããã確èªããŸãã ããã¹ããã£ãŒã«ããæŽæ°ããå¿
èŠããªãå Žåã¯ããã®ããã¥ã¡ã³ãã«å¯ŸããŠUPDATE
ã¯ãšãªãäœæããããã§ãªãå Žåã¯REPLACE
ãŸãã
binlogããèªã¿åã£ããã¹ãŠã®å€æŽãé©çšããªãç¶æ³ãçºçããå¯èœæ§ããããããããã§ã¯ã倱æããå Žåã«binlogã®èªã¿åããéå§ã§ããäœçœ®ãç¶æããããžãã¯ãè€éã«ããå¿
èŠãããããšã«æ³šæããŠãã ããã
binlogã®èªã¿åããæ£åžžã«åéããããã«ã次ã®ããšãè¡ããŸãããããŒã¿ããŒã¹å
ã®è¡å€æŽã€ãã³ãããšã«ããã®ã€ãã³ããçºçããæç¹ã§æåŸã«å®äºãããã©ã³ã¶ã¯ã·ã§ã³ã®IDãèŠããŠãããŠãã ããã å€æŽãSphinxã«éä¿¡ããåŸã次ã®ããã«ãå®å
šã«èªã¿åããéå§ã§ãããã©ã³ã¶ã¯ã·ã§ã³çªå·ãæŽæ°ããŸãã èç©ããããã¹ãŠã®å€æŽãåŠçããªãã£ãå ŽåïŒäžéšã®ããã¥ã¡ã³ãããã¥ãŒã§ã远跡ããããªãã£ãããïŒããŸã é©çšã§ããŠããªãå€æŽã«é¢é£ãããã©ã³ã¶ã¯ã·ã§ã³ããæãæ©ããã©ã³ã¶ã¯ã·ã§ã³ã®æ°ãååŸããŸãã ãããŠãèç©ããããã¹ãŠã®å€æŽãé©çšããå Žåã¯ãæåŸã«å®äºãããã©ã³ã¶ã¯ã·ã§ã³ã®çªå·ãååŸããŸãã
çµæãšããŠäœãèµ·ãã£ãã®ãã¯ç§ãã¡ã«åã£ãŠããŸãããããã1ã€éèŠãªç¹ããããŸããããªã¢ã«ã¿ã€ã ã€ã³ããã¯ã¹ã®ããã©ãŒãã³ã¹ãé·æã«ããã£ãŠèš±å®¹ã¬ãã«ã«ç¶æããã«ã¯ããã®ã€ã³ããã¯ã¹ã®ããã£ã³ã¯ãã®ãµã€ãºãšæ°ãå°ããããå¿
èŠããããŸããã ãããè¡ãããã«ãSphinxã«ã¯ãæ°ãããã£ã¹ã¯ãã£ã³ã¯ãäœæããFLUSH RAMCHUNK
ãªã¯ãšã¹ããšããã¹ãŠã®ãã£ã¹ã¯ãã£ã³ã¯ã1ã€ã«ããŒãžããOPTIMIZE INDEX
ãªã¯ãšã¹ãããããŸãã æåã¯ãå®æçã«å®è¡ããã ãã ãšæã£ãŠããŸããããããã ãã§ãã ããããæ®å¿µãªããšã«ãããŒãžã§ã³2.3.2ã§ã¯ãã€ã³ããã¯ã¹ã®æé©åã¯æ©èœããŸããïŒã€ãŸããããªãé«ã確çã§searchdãäœäžããããšãå€æããŸããïŒã ãã®ãããç¹ã«ã€ã³ããã¯ã¹ã¹ããŒã ãããŒã¯ãã€ã¶ãŒã®èšå®ãå€æŽãããå Žåãªã©ãç¹ã«å¿
èŠãªå Žåããããããã€ã³ããã¯ã¹ã1æ¥ã«1åå®å
šã«åæ§ç¯ããããšã«ããŸããã
ã€ã³ããã¯ã¹ãåæ§ç¯ããæé ã¯ãããã€ãã®æ®µéã§è¡ãããŸãã
ã€ã³ãã¯ãµãŒã®æ§æãçæããŸã
äžèšã®ããã«ããµãŒãã¹æ§æã«ã¯SQLã¯ãšãªãã³ãã¬ãŒãããããŸãã ãŸããã€ã³ãã¯ãµãŒæ§æã®åœ¢æã«ã䜿çšãããŸãã
ãŸããæ§æã«ã¯ãã€ã³ããã¯ã¹ã®äœæã«å¿
èŠãªä»ã®èšå®ïŒããŒã¯ã³èšå®ãèŸæžããªãœãŒã¹æ¶è²»ã®ããŸããŸãªå¶éïŒããããŸãã
MariaDBã®çŸåšã®äœçœ®ãä¿åãã
ãã®äœçœ®ãããsearchdã䜿çšããŠãã¹ãŠã®ãµãŒããŒã§æ°ããã€ã³ããã¯ã¹ã䜿çšå¯èœã«ãªã£ãåŸãbinlogã®èªã¿åããéå§ããŸãã
ã€ã³ãã¯ãµãŒãéå§ããŸã
indexer --config tmp.vacancy.indexer.0.conf --all
圢åŒã®ã³ãã³ãindexer --config tmp.vacancy.indexer.0.conf --all
ããå®äºãåŸ
ã¡ãŸãã ããã«ãã€ã³ããã¯ã¹ãéšåã«åå²ãããŠããå Žåããã¹ãŠã®éšåã®æ§ç¯ã䞊è¡ããŠéå§ããŸãã
ãµãŒããŒã«ã€ã³ããã¯ã¹ãã¡ã€ã«ãããŒãããŸã
åãµãŒããŒãžã®ã¢ããããŒãã䞊è¡ããŠè¡ãããŸããããã¹ãŠã®ãã¡ã€ã«ããã¹ãŠã®ãµãŒããŒã«ã¢ããããŒãããããŸã§èªç¶ã«åŸ
æ©ããŸãã ãµãŒãã¹èšå®ã®ãã¡ã€ã«ãããŠã³ããŒãããã«ã¯ããã¡ã€ã«ãããŠã³ããŒãããããã®ã³ãã³ããã³ãã¬ãŒãã®ã»ã¯ã·ã§ã³ããããŸãã
[index_uploader] executable = "rsync" arguments = [ "--files-from=-", "--log-file=<<.DataDir>>/rsync.<<.Host>>.log", "--no-relative", "--times", "--delay-updates", ".", "rsync://<<.Host>>/index/vacancy/", ]
ãµãŒããŒããšã«ãåã«ãã¹ãå€æ°ã®ååã«çœ®ãæããŠãçµæã®ã³ãã³ããå®è¡ããŸãã ããŠã³ããŒãã«ã¯rsyncã䜿çšããŸãããååãšããŠãstdinå
ã®ãã¡ã€ã«ã®ãªã¹ããåãå
¥ãããããã®ãã¡ã€ã«ãsearchdãã€ã³ããã¯ã¹ãã¡ã€ã«ãåç
§ããããšãæåŸ
ãããã©ã«ããŒã«ããŠã³ããŒãããããã°ã©ã ãŸãã¯ã¹ã¯ãªããã§ãã
åæãåæ¢ããŸã
binlogã®èªã¿åããåæ¢ããå€æŽã®èç©ãæ
åœãããŽã«ãŒãã³ãåæ¢ããŸãã
å€ãã€ã³ããã¯ã¹ãæ°ããã€ã³ããã¯ã¹ã«çœ®ãæããŸã
searchdã䜿çšãããµãŒããŒããšã«ãé 次ã¯ãšãªRELOAD INDEX vacancy_plain
ã TRUNCATE INDEX vacancy_plain
ã ATTACH INDEX vacancy_plain TO vacancy
ãŸãã ã€ã³ããã¯ã¹ãããŒãã«åå²ãããŠããå ŽåãåããŒãã«å¯ŸããŠãããã®ã¯ãšãªãé çªã«å®è¡ããŸãã åæã«ãæ¬çªç°å¢ã«ããå Žåã¯ããµãŒããŒã§ãããã®ã¯ãšãªãå®è¡ããåã«ããã©ã³ãµãŒãä»ããŠè² è·ãåãé€ããŸãïŒãããã£ãŠã TRUNCATE
ãšATTACH
éã®ã€ã³ããã¯ã¹ã«å¯ŸããŠSELECTã¯ãšãªãäœæããªãããã«ããŸãïŒæåŸã®ATTACH
èŠæ±ãå®äºãããšããã®ãµãŒããŒã«è² è·ãè¿ãããŸãã
ä¿åããäœçœ®ããåæãåéãã
ãã¹ãŠã®ãªã¢ã«ã¿ã€ã ã€ã³ããã¯ã¹ãæ°ããäœæããã€ã³ããã¯ã¹ã«çœ®ãæãããšããã«ãbinlogããèªã¿åããåéããbinlogããã®ã€ãã³ããåæããŸããã€ã³ããã¯ã¹äœæãå§ãŸãåã«ä¿åããäœçœ®ããéå§ããŸãã
以äžã«ãMariaDBãµãŒããŒããã®ã€ã³ããã¯ã¹ã®ã©ã°ã®ã°ã©ãã®äŸã瀺ããŸãã

ããã§ãåæ§ç¯åŸã®ã€ã³ããã¯ã¹ã®ç¶æ
ã¯æéå
ã«æ»ã£ãŠããŸãããããã¯éåžžã«çæéã§çºçããããšãããããŸãã
ã»ãŒãã¹ãŠã®æºåãæŽã£ãã®ã§ããªãªãŒã¹ã®æéã§ãã åŸã
ã«ãã£ãã ãŸããããã€ãã®ãµãŒããŒã«ãªã¢ã«ã¿ã€ã ã€ã³ããã¯ã¹ãæµã蟌ã¿ãŸãããããã®ãšãã®æ®ãã¯åãããã«æ©èœããŸããã åæã«ããæ°ããããµãŒããŒäžã®ã€ã³ããã¯ã¹ã®æ§é ã¯å€ããã®ãšå€ãããªãã£ããããPHPã¢ããªã±ãŒã·ã§ã³ã¯ããªã¯ãšã¹ãããªã¢ã«ã¿ã€ã ã€ã³ããã¯ã¹ã§åŠçãããããã¬ãŒã³ã€ã³ããã¯ã¹ã§åŠçãããããå¿é
ããã«ãã©ã³ãµãŒã«æ¥ç¶ã§ããŸããã

以åã«èª¬æããå±æ§ã®æŽæ°ãå€ãã¹ããŒã ã«åŸã£ãŠéä¿¡ãããŸãããããã¹ãŠã®ãµãŒããŒã®åæ£ã€ã³ããã¯ã¹ã¯ããã¬ãŒã³ã€ã³ããã¯ã¹ãæã€ãµãŒããŒã«ã®ã¿UPDATEã¯ãšãªãéä¿¡ããããã«æ§æãããŠããŸããã ããã«ãã¢ããªã±ãŒã·ã§ã³ããã®UPDATEèŠæ±ããªã¢ã«ã¿ã€ã ã€ã³ããã¯ã¹ã䜿çšããŠãµãŒããŒã«å°éããå Žåããã®èŠæ±ã¯å®è¡ããããå€ãæ¹æ³ã§æ§æããããµãŒããŒã«éä¿¡ãããŸãã
ãªãªãŒã¹åŸãç§ãã¡ãæãã§ããããã«ãããŒã¿ããŒã¹ã®åéãŸãã¯ç©ºåžã®å€æŽãšã察å¿ããå€æŽãã€ã³ããã¯ã¹ã«åæ ããããŸã§ã®é
延ã倧å¹
ã«åæžããããšãããããŸããã
ãªã¢ã«ã¿ã€ã ã€ã³ããã¯ã¹ã«åãæ¿ããåŸããã¹ããµãŒããŒã§å€æŽãè¡ããã³ã«ã€ã³ããã¯ã¹ãåæ§ç¯ããå¿
èŠã¯ãããŸããã§ããã ãã®ãããæ¯èŒçå®äŸ¡ã«æ€çŽ¢ã«åå ããŠããšã³ãããŒãšã³ãã®èªåãã¹ããäœæããããšãå¯èœã«ãªããŸããã ãã ããïŒããŒã¿ããŒã¹ã«æžã蟌ãã¯ã©ã€ã¢ã³ãã®èŠ³ç¹ããïŒbinlogããã®å€æŽãéåæçã«åŠçãããããèªåãã¹ãã«åå ããŠããããã¥ã¡ã³ãã«é¢ããå€æŽããµãŒãã¹ã«ãã£ãŠåŠçãããsearchdã«éä¿¡ããããŸã§åŸ
æ©ã§ããããã«ããå¿
èŠããããŸããã
ãããè¡ãããã«ããµãŒãã¹ã§ãšã³ããã€ã³ããäœæããŸãããããã¯ãŸãã«ãããè¡ããŸããã€ãŸããæå®ããããã©ã³ã¶ã¯ã·ã§ã³çªå·ã«ãã¹ãŠã®å€æŽãé©çšããããŸã§åŸ
æ©ããŸãã ãããè¡ãã«ã¯ãããŒã¿ããŒã¹ã«å¿
èŠãªå€æŽãå ããçŽåŸã«ãMariaDB @@gtid_current_pos
ãªã¯ãšã¹ãããããããµãŒãã¹ã®ãšã³ããã€ã³ãã«è»¢éããŸãã ãã®æç¹ãŸã§ã«ãã¹ãŠã®ãã©ã³ã¶ã¯ã·ã§ã³ããã®äœçœ®ã«æ¢ã«é©çšããŠããå ŽåããµãŒãã¹ã¯ããã«å¿çããŠç¶è¡ã§ãããšçããŸãã ããã§ãªãå Žåã¯ãå€æŽã®é©çšãæ
åœãããŽã«ãŒãã³ã§ããã®GTIDãžã®ãµãã¹ã¯ãªãã·ã§ã³ãäœæããããïŒãŸãã¯ããã«ç¶ãããããïŒãé©çšããããšããã«ãã¯ã©ã€ã¢ã³ããèªåãã¹ããç¶è¡ã§ããããã«ããŸãã
PHPã³ãŒãã§ã¯ã次ã®ããã«ãªããŸãã
<?php declare(strict_types=1); use GuzzleHttp\ClientInterface; use GuzzleHttp\RequestOptions; use PDO; class RiverClient { private const REQUEST_METHOD = 'post'; /** * @var ClientInterface */ private $httpClient; public function __construct(ClientInterface $httpClient) { $this->httpClient = $httpClient; } public function waitForSync(PDO $mysqlConnection, PDO $sphinxConnection, string $riverAddr): void { $masterGTID = $mysqlConnection->query('SELECT @@gtid_current_pos')->fetchColumn(); $this->httpClient->request( self::REQUEST_METHOD, "http://{$riverAddr}/wait", [RequestOptions::FORM_PARAMS => ['gtid' => $masterGTID]] ); } }
çµæ
ãã®çµæãMariaDBãšSphinxã®æŽæ°éã®é
延ã倧å¹
ã«åæžããããšãã§ããŸããã


ãŸãããã¹ãŠã®æŽæ°ããã¹ãŠã®SphinxãµãŒããŒã«æééãã«å±ããšç¢ºä¿¡ããããã«ãªããŸããã
ããã«ãæ€çŽ¢ãã¹ãïŒæåãšèªåã®äž¡æ¹ïŒãã¯ããã«æ¥œãããªããŸããã
æ®å¿µãªãããããã¯ç¡æã§ã¯æäŸãããŸããã§ããããªã¢ã«ã¿ã€ã ã€ã³ããã¯ã¹ã®ããã©ãŒãã³ã¹ã¯ããã¬ãŒã³ã€ã³ããã¯ã¹ã«æ¯ã¹ãŠãããã«å£ã£ãŠããŸããã
åçŽãªã€ã³ããã¯ã¹ã®æéã«å¿ããæ€çŽ¢ã¯ãšãªã®åŠçæéã®ååžã以äžã«ç€ºããŸãã

ãããŠãããããªã¢ã«ã¿ã€ã ã€ã³ããã¯ã¹ã®åããã£ãŒãã§ãã

ãé«éããªã¯ãšã¹ãã®ã·ã§ã¢ããããã«æžå°ãããäœéããªã¯ãšã¹ãã®ã·ã§ã¢ãå¢å ããŠããããšãããããŸãã
çµè«ã®ä»£ããã«
ãã®èšäºã§èª¬æãããŠãããµãŒãã¹ã®ã³ãŒãã¯ããããªãã¯ãã¡ã€ã³ã«æçš¿ãããŠãããšèšãããšã¯ã§ããŸããã æ®å¿µãªããã詳现ãªããã¥ã¡ã³ãã¯ãŸã ãããŸããããå¿
èŠã«å¿ããŠã docker-compose
ã䜿çšããŠãã®ãµãŒãã¹ã®äœ¿çšäŸãå®è¡ã§ããŸãã
åç
§è³æ
- ãããªãšã¬ããŒãã®ã¹ã©ã€ã
- Highload ++ã«é¢ããAndrey SmirnovãšVyacheslav Kryukovã«ãããããªã¬ããŒã
- Go-mysqlã©ã€ãã©ãª
- 䜿çšäŸä»ãã®ãµãŒãã¹ã³ãŒã