如何使用 Elasticsearch 6.2 搜索中文、日语和韩语文本 - 第 3 部分:语言检测工具

这是我有关中文、日语和韩语文本搜索的系列文章的第 3 部分。如果您还没有阅读有关分析工具的第 1 部分,您可能希望先阅读这一部分。如果您已阅读完第 1 部分,如何使用 Elasticsearch 6.2 搜索中文、日语和韩语文本 - 第 2 部分:多字段介绍了通过多字段对以多种语言编写的文档进行索引和搜索的方法。然而,如果不管任何语言,我们都将文本存储在四个字段内并使用四种分析工具进行分析,这可能会浪费我们的宝贵时间和存储空间。现在,我们将尝试通过语言检测工具来进行优化。和之前一样,文本仍然节选自 https://www.pyeongchang2018.com/en/about-the-games

语言检测工具

我们可以安装并利用可检测语言的摄取插件来节省时间和存储空间。下面的摄取管道会检测“正文”字段的语言并且会通过语言检测处理器将检测到的语言放到“语言”字段中,而非将其索引至主字段和三个子字段中。然后脚本处理器会将“正文”字段的内容复制到具体语言的字段中(english_field、korean_field、japanese_field 或 chinese_field)进行分析。

PUT _ingest/pipeline/langdetect-pipeline
{
  "description": "A pipeline to do whatever",
  "processors": [
    {
      "langdetect": {
        "field": "body",
        "target_field": "language"
      }
    },
    {
      "script": {
        "lang": "painless",
        "source": "if (ctx.language == 'ko') ctx.korean_field = ctx.body; if (ctx.language == 'ja') ctx.japanese_field = ctx.body; if (ctx.language == 'zh-cn') ctx.chinese_field = ctx.body; if (ctx.language == 'en') ctx.english_field = ctx.body;"
      }
    }
  ]
}

在本篇博客文章中,我使用的是 kuromojismartcnopenkoreantext-analyzer;您也要首先安装这些插件,然后才能创建下面的索引。

DELETE test2
PUT /test2
{  
  "mappings": {
    "docs": {
      "properties": {
        "body": {
          "type": "text"
        },
        "english_field": {
          "type": "text"
        },
        "korean_field": {
          "analyzer": "openkoreantext-analyzer",
          "type": "text"
        },
        "japanese_field": {
          "analyzer": "kuromoji",
          "type": "text"
        },
        "chinese_field": {
          "analyzer": "smartcn",
          "type": "text"
        }
      }
    }
  }
}

对文档进行索引时,您应当指明使用语言检测工具的 langdetect-pipeline 管道。

PUT /test2/docs/1?pipeline=langdetect-pipeline
{
  "body" : "The XXIII Olympic Winter Games will be held for 17 days from 9 to 25 February 2018 in PyeongChang, Gangwon Province, the Republic of Korea. PyeongChang was selected as the host city of the 2018 Olympic Winter Games after receiving a majority vote at the 123rd IOC Session held on 6 July 2011 after three consecutive bids. The Olympic Winter Games will be held in Korea for the first time in 30 years after the Seoul Olympic Games in 1988. PyeongChang will be the stage for the Opening and Closing Ceremonies and most snow sports. Alpine speed events will take place in Jeongseon, and all ice sports will be competed in the coastal city of Gangneung."
}
PUT /test2/docs/2?pipeline=langdetect-pipeline
{
  "body" : "제23회 동계올림픽대회는 대한민국 강원도 평창에서 2018년 2월 9일부터 25일까지 17일간 개최됩니다. 대한민국 평창은 세 번의 도전 끝에 지난 2011년 7월 6일 열린 제123차 IOC 총회에서 과반 표를 획득하며 2018년 동계올림픽 개최지로 선정되었습니다. 이로써 대한민국에서는 1988년 서울 올림픽 이후 30년 만에, 평창에서 개∙폐회식과 대부분의 설상 경기가 개최되며, 강릉에서는 빙상 종목 전 경기가, 그리고 정선에서는 알파인 스키 활강 경기가 개최될 예정입니다."
}
PUT /test2/docs/3?pipeline=langdetect-pipeline
{
  "body" : "第23届冬季奥运会将于2018年2月9日-25日在韩国江原道平昌展开。韩国平昌在第三次申奥之后,于2011年7月6日召开的第123届国际奥委会全会上被选定为2018年冬季奥运会的主办地。由此,韩国自1988年举办首尔夏季奥运会以后,时隔30年,将首次举办冬季奥运会。该届冬奥会的开·闭幕式以及大部分的雪上运动将在平昌进行,而所有冰上运动将在江陵、高山滑雪滑降比赛则将在旌善进行。"
}
PUT /test2/docs/4?pipeline=langdetect-pipeline
{
  "body" : "第23回冬季オリンピック大会は大韓民国江原道平昌で2018年2月9日から25日までの17日間、開催されます。大韓民国・平昌は三度の挑戦の末、2011年7月7日に開かれた第123回IOC総会で過半数票を獲得し、2018年冬季オリンピック及びパラリンピックの開催地に選ばれました。これにより1988年ソウルオリンピック開催後30年の時を経てついに、大韓民国で最初の冬季パラリンピックの舞台が繰り広げられます。平昌で開・閉会式とほぼ全ての雪上競技が開催され、江陵では氷上種目全競技が、そして旌善ではアルペンスキー滑降競技が開催される予定です。"
}

示例: 如果“正文”字段的内容是韩语,则会将其复制到 korean_field,如下所示:

GET /test2/docs/2
=>
{
  "_index": "test",
  "_type": "docs",
  "_id": "2",
  "_version": 1,
  "found": true,
  "_source": {
    "language": "ko",
    "body": "제23회 동계올림픽대회는 대한민국 강원도 평창에서 2018년 2월 9일부터 25일까지 17일간 개최됩니다. 대한민국 평창은 세 번의 도전 끝에 지난 2011년 7월 6일 열린 제123차 IOC 총회에서 과반 표를 획득하며 2018년 동계올림픽 개최지로 선정되었습니다. 이로써 대한민국에서는 1988년 서울 올림픽 이후 30년 만에, 평창에서 개∙폐회식과 대부분의 설상 경기가 개최되며, 강릉에서는 빙상 종목 전 경기가, 그리고 정선에서는 알파인 스키 활강 경기가 개최될 예정입니다.",
    "korean_field": "제23회 동계올림픽대회는 대한민국 강원도 평창에서 2018년 2월 9일부터 25일까지 17일간 개최됩니다. 대한민국 평창은 세 번의 도전 끝에 지난 2011년 7월 6일 열린 제123차 IOC 총회에서 과반 표를 획득하며 2018년 동계올림픽 개최지로 선정되었습니다. 이로써 대한민국에서는 1988년 서울 올림픽 이후 30년 만에, 평창에서 개∙폐회식과 대부분의 설상 경기가 개최되며, 강릉에서는 빙상 종목 전 경기가, 그리고 정선에서는 알파인 스키 활강 경기가 개최될 예정입니다."
  }
}

使用多字段的话,我们可以得到相似的搜索结果。这里用到了源文本筛选来筛选结果:

韩语

POST /test2/_search
{
  "query": {
    "multi_match": {
      "query": "올림픽대회",
      "fields": [
        "english_field",
        "korean_field",
        "chinese_field",
        "japanese_field"
      ]
    }
  },
  "_source": "body"
}
=>
...
  "hits": {
    "total": 1,
    "max_score": 0.57860667,
    "hits": [
      {
        "_index": "test",
        "_type": "docs",
        "_id": "2",
        "_score": 0.57860667,
        "_source": {
          "body": "제23회 동계올림픽대회는 대한민국 강원도 평창에서 2018년 2월 9일부터 25일까지 17일간 개최됩니다. 대한민국 평창은 세 번의 도전 끝에 지난 2011년 7월 6일 열린 제123차 IOC 총회에서 과반 표를 획득하며 2018년 동계올림픽 개최지로 선정되었습니다. 이로써 대한민국에서는 1988년 서울 올림픽 이후 30년 만에, 평창에서 개∙폐회식과 대부분의 설상 경기가 개최되며, 강릉에서는 빙상 종목 전 경기가, 그리고 정선에서는 알파인 스키 활강 경기가 개최될 예정입니다."
        }
      }
    ]
  }
}

英语

POST /test2/_search
{
  "query": {
    "multi_match": {
      "query": "Olympic Games",
      "fields": [
        "english_field",
        "korean_field",
        "chinese_field",
        "japanese_field"
      ]
    }
  },
  "_source": "body"
}
=>
...
  "hits": {
    "total": 1,
    "max_score": 0.97953933,
    "hits": [
      {
        "_index": "test",
        "_type": "docs",
        "_id": "1",
        "_score": 0.97953933,
        "_source": {
          "body": "The XXIII Olympic Winter Games will be held for 17 days from 9 to 25 February 2018 in PyeongChang, Gangwon Province, the Republic of Korea. PyeongChang was selected as the host city of the 2018 Olympic Winter Games after receiving a majority vote at the 123rd IOC Session held on 6 July 2011 after three consecutive bids. The Olympic Winter Games will be held in Korea for the first time in 30 years after the Seoul Olympic Games in 1988. PyeongChang will be the stage for the Opening and Closing Ceremonies and most snow sports. Alpine speed events will take place in Jeongseon, and all ice sports will be competed in the coastal city of Gangneung."
        }
      }
    ]
  }
}

日语

POST /test2/_search
{
  "query": {
    "multi_match": {
      "query": "オリンピック大会",
      "fields": [
        "english_field",
        "korean_field",
        "chinese_field",
        "japanese_field"
      ]
    }
  },
  "_source": "body"
}
=>
...
  "hits": {
    "total": 1,
    "max_score": 0.7469032,
    "hits": [
      {
        "_index": "test2",
        "_type": "docs",
        "_id": "4",
        "_score": 0.7469032,
        "_source": {
          "body": "第23回冬季オリンピック大会は大韓民国江原道平昌で2018年2月9日から25日までの17日間、開催されます。大韓民国・平昌は三度の挑戦の末、2011年7月7日に開かれた第123回IOC総会で過半数票を獲得し、2018年冬季オリンピック及びパラリンピックの開催地に選ばれました。これにより1988年ソウルオリンピック開催後30年の時を経てついに、大韓民国で最初の冬季パラリンピックの舞台が繰り広げられます。平昌で開・閉会式とほぼ全ての雪上競技が開催され、江陵では氷上種目全競技が、そして旌善ではアルペンスキー滑降競技が開催される予定です。"
        }
      }
    ]
  }
}

中文

POST /test2/_search
{
  "query": {
    "multi_match": {
      "query": "奥运会",
      "fields": [
        "english_field",
        "korean_field",
        "chinese_field",
        "japanese_field"
      ]
    }
  },
  "_source": "body"
}
=>
...
  "hits": {
    "total": 1,
    "max_score": 0.49148652,
    "hits": [
      {
        "_index": "test2",
        "_type": "docs",
        "_id": "3",
        "_score": 0.49148652,
        "_source": {
          "body": "第23届冬季奥运会将于2018年2月9日-25日在韩国江原道平昌展开。韩国平昌在第三次申奥之后,于2011年7月6日召开的第123届国际奥委会全会上被选定为2018年冬季奥运会的主办地。由此,韩国自1988年举办首尔夏季奥运会以后,时隔30年,将首次举办冬季奥运会。该届冬奥会的开·闭幕式以及大部分的雪上运动将在平昌进行,而所有冰上运动将在江陵、高山滑雪滑降比赛则将在旌善进行。"
        }
      }
    ]
  }
}

请注意:由于我们搜索的只是通过具体语言分析工具分析的字段,所以当我们查询日语关键词时,我们只会得到日语文档,同理当我们查询中文关键词时,我们仅会得到中文文档。这与多字段方式有所不同,有关多字段方式,详见如何使用 Elasticsearch 6.2 搜索中文、日语和韩语文本 - 第 2 部分:多字段

担心耗时过长?

如果您担心索引或查询的时间,虽然与使用单字段相比,使用多字段或语言检测工具进行索引时耗时会稍长一点,但是其实它们之间的差别并不大。

index-time.png

图 1 - 索引 500 份文档所用的时间(MacBook Pro,2.9 GHz Intel Core i7, 16GB 2133 MHz LPDDR3)

使用多字段或语言检测工具查询所用的时间与使用单字段查询所用的时间基本相同。

query-time.png

图 2 - 进行 500 次查询所用的时间 (MacBook Pro,2.9 GHz Intel Core i7, 16GB 2133 MHz LPDDR3)

通过语言检测工具,我们能够实现比多字段方法更佳的搜索结果,而且还可节省存储空间。Elasticsearch 6.x 甚至还有“稀疏字段改进措施”功能(详见 Elasticsearch 6.0 可节省空间的改善措施)。

附录

multi-lang-scripts.zip

  • index.sh - 测量索引时间的脚本
  • query.sh - 测量查询时间的脚本