Skip to content

Instantly share code, notes, and snippets.

@masazdream
Created August 19, 2014 11:04
Show Gist options
  • Select an option

  • Save masazdream/3e516bda716bee4ba9ad to your computer and use it in GitHub Desktop.

Select an option

Save masazdream/3e516bda716bee4ba9ad to your computer and use it in GitHub Desktop.
TextMatchingする昔つくったphpクラス
<?php
/**
* テキストマッチングのクラス
*
* @author kiban
*
*
*/
class pjTextmatching
{
/**
* テキストのマッチング率を取得する
*
* @param $inquiry 質問オブジェクト
* @param $engine エンジンの種類(4または5)
*
* @return エンジンが不正な場合 false
* 質問のOCRテキストが空の場合 false
* $org_ocr_ranking[連番(0はじまり)][image_search_id][score] (scoreの降順)
*/
public static function getTextMachingResult($inquiry, $engine){
// 検索用OCRテキストの配列
$ocr_array = array();
$search_images = MImageSearchTable::getImageSearchBySubjectIdAll($inquiry->getSubjectId());
// 検索用OCRテキストの配列を作成
foreach($search_images as $search_image){
$id = $search_image->getImageSearchId();
$ocr_text = '';
// engineの配列を取得
$index_array = sfConfig::get('app_search_engine_index');
// 対応engineかどうか判別する
$file_suffix = '';
if($engine == $index_array['vector_auto']){
$ocr_text = $search_image->getOcrAllText();
$file_suffix = '_a';
}else if($engine == $index_array['vector_hand']){
$ocr_text = $search_image->getHandAllText();
$file_suffix = '_h';
}else{
return false;
}
$ocr_array[$id] = $ocr_text;
}
// マッチング用ファイルの作成ディレクトリ
$dir = sfConfig::get('app_ocr_matching');
// 質問のOCRテキストを取得する
//$inquiry = TInquiryTable::getInquiryByIdAdmin($inquiry_id);
$inquiry_id = $inquiry->getInquiryId();
$text_file_name = $dir . $inquiry_id . '.txt';
$inq_ocr = $inquiry->getOcrText();
// 0文字だったらfalseで返す
if(mb_strlen($inq_ocr) == 0){
return false;;
}
// 結果配列を作成
$org_ocr_ranking = array();
// 質問のOCRファイルを新しく作成する
$makeFile_result = self::makeFile($text_file_name, $inq_ocr);
if(!$makeFile_result){
return false;
}
// 質問のOCRを形態素解析する
$bash1 = '/usr/local/bin/mecab ' . $text_file_name;
$mecab_rt1 = shell_exec($bash1);
// 質問用ファイルを削除する、結果に関係なく処理を続ける
$removeFile_result = self::removeFile($text_file_name);
// 検索用OCRテキストの配列でループ
$i=0;
foreach($ocr_array as $key=>$value){
// 検索用OCRのIDをファイル名にする
$ocr_file_name = $dir . $key . $file_suffix . '.txt';
// マッチング用ファイルを作成
$make_ocr_file_result = self::makeFile($ocr_file_name, $value);
if(!$make_ocr_file_result){
// あるocr検索用のファイルが失敗しても処理は続ける
}
// 形態素解析する
$bash2 = '/usr/local/bin/mecab ' . $ocr_file_name;
$mecab_rt2 = shell_exec($bash2);
// マッチングをかける
$similarity = self::textmatching($mecab_rt1,$mecab_rt2);
if($similarity == 0){
continue;
}
$org_ocr_ranking[$i]['image_search_id'] = $key;
$org_ocr_ranking[$i]['score'] = $similarity;
$org_ocr_sort_key[$i] = $similarity;
$i++;
}
if(!empty($org_ocr_ranking)){
array_multisort($org_ocr_sort_key, SORT_DESC, SORT_NUMERIC, $org_ocr_ranking, SORT_ASC, SORT_STRING);
}
return $org_ocr_ranking;
}
/**
* OCRテキスト格納用のファイルを作成する
*
* @param $text_file_name 作成するファイルのパス
* @param $ocr ocrに使用するテキスト
*
*/
public static function makeFile($text_file_name, $ocr){
// ファイルの存在確認
// if(file_exists($text_file_name)){
// return true;
// }
$fp = fopen($text_file_name, 'w+', true);
if ($fp){
if (flock($fp, LOCK_EX)){
if (fwrite($fp, $ocr) === FALSE){
return false;
}
flock($fp, LOCK_UN);
}else{
//print('ファイルロックに失敗しました');
return false;
}
}
fclose($fp);
return true;
}
/**
* 質問用ファイルを削除する
*
* @param unknown $text_file_name
*/
public static function removeFile($text_file_name){
// ファイルの存在確認
if(file_exists($text_file_name)){
try{
if(!unlink($text_file_name)){
return false;
}
}catch(Exception $e){
sfContext::getInstance()->getLogger()->err($e);
return false;
}
}
}
/**
* 2つのmecab結果のベクトル内積を計算し、正規化を行う。
*
* @param $mecab_rt1 テキスト1
* @param $mecab_rt2 テキスト2
*/
public static function textmatching($mecab_rt1, $mecab_rt2){
// 改行コードで分けて配列に格納する
$mecab_array1 = explode("\n", $mecab_rt1);
$mecab_array2 = explode("\n", $mecab_rt2);
$word_list = array();
foreach($mecab_array1 as $words1){
$word_array1 = explode(",", $words1);
$type = $word_array1[0];
if($type == 'EOS'){
break;
}
if(count($word_array1) > 5){
$value = $word_array1[6];
}else{
$value = 'no valid word.';
}
$type_name = explode("\t", $type);
if(count($type_name) > 1){
$prop = $type_name[1];
}else{
$prop = $type_name[0];
}
if(($prop=='名詞' or $prop=='動詞' or $prop=='形容詞') and $value !='*' ){
if(array_key_exists($value, $word_list)){
$word_list[$value] = $word_list[$value] + 1;
}else{
$word_list[$value] = '1';
}
}
}
$word_list2 = array();
foreach($mecab_array2 as $words2){
$word_array2 = explode(",", $words2);
$type = $word_array2[0];
if($type == 'EOS'){
break;
}
if(count($word_array2) > 5){
$value = $word_array2[6];
}else{
$value = 'no valid word.';
}
$type_name = explode("\t", $type);
if(count($type_name) > 1){
$prop = $type_name[1];
}else{
$prop = $type_name[0];
}
if(($prop=='名詞' or $prop=='動詞' or $prop=='形容詞') and $value !='*' ){
if(array_key_exists($value, $word_list2)){
$word_list2[$value] = $word_list2[$value] + 1;
}else{
$word_list2[$value] = '1';
}
}
}
if(empty($word_list) or empty($word_list)){
$error_message = '有効な単語を含みません';
return $error_message;
}
// 各スケールベクトルを作成
$vector1 = 0;
foreach($word_list as $word=>$value){
$vector1 += pow($value, 2);
}
$scale1 = sqrt($vector1);
$vector2 = 0;
foreach($word_list2 as $word=>$value){
$vector2 += pow($value, 2);
}
$scale2 = sqrt($vector2);
// 内積をとる
$inner = 0;
foreach($word_list as $word=>$value){
if(array_key_exists($word, $word_list2)){
$score1 = $value;
$score2 = $word_list2[$word];
$inner += ($score1 * $score2);
}
}
$similarity = 0;
if(($scale1 * $scale2) != 0){
$similarity = $inner / ($scale1 * $scale2);
}
return $similarity;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment