Created
August 19, 2014 11:04
-
-
Save masazdream/3e516bda716bee4ba9ad to your computer and use it in GitHub Desktop.
TextMatchingする昔つくったphpクラス
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?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