본문 바로가기
PHP

[PHP] FullText-Search 처리하는 방법

by teamnova 2024. 1. 23.
728x90

안녕하세요 오늘은 FullText-Search 처리를 하는 방법에 대해 알아보겠습니다.

 

저희는 MYSQL을 사용할 때, LIKE 연산을 통한 패턴 일치 검색을 사용하는데요.

하지만 저번에 보여드린 인덱스 처리를 하다보면 검색에 조금 제한이 생기기 마련입니다.

https://stickode.tistory.com/1036

 

이럴 때 고려해볼 수 있는 것이 바로 전문 검색, FullText-Search입니다.

이것은 단어 또는 구문에 대한 검색을 의미하며, 게시물 내용이나 제목 등과 같이 문서 내 키워드를 검색할 수 있습니다.

 

정리하자면 FullText-Search는 첫 글자 뿐 아니라 중간의 단어나 문장으로도 인덱스를 생성해 주기 때문에 순식간에 검색 결과를 얻을 수 있다.
InnoDB와 MyISAM 테이블에 지원하고 char, varchar, text 타입 문자만 인덱싱이 가능합니다.

 

생성 방식은 다양하지만 다음과 같이 이전에 인덱스 처리방법 게시글에서 사용한 방식과 같은 방식을 사용해보겠습니다.

CREATE FULLTEXT INDEX 인덱스이름 ON 테이블이름 (열이름);

 

 

예제는 다음과 같습니다.

addFullTextIndexToTitle() 메소드에서 FullText Index를 추가해주고

그것을 활용해 selectByTitle() 메소드에서 전체 문자 검색을 하는 방법입니다.

class Database { // 데이터베이스 관련 클래스
	
	private $host_name = "localhost";
	private $host_id = "root";
	private $host_password = "root";
	private $db_name = "test";
	private $conn;

	private function __construct() { // db 객체 초기화
		$this->conn = mysqli_connect($this->host_name, $this->user_name, $this->user_password);
		mysqli_select_db($this->conn, $this->db_name);
		mysqli_set_charset($this->conn, "utf8");		
    	}

	public function get_insert_id() { // 저장된 마지막 PK 값 가져오는 메소드
		$id = mysqli_insert_id($this->conn);
		return $id;
	}
    
	public function addFullTextIndexToTitle(){ // 검색 시 자주 사용하는 title에 FullText-Search용 인덱스를 추가하는 메소드
		$query = "CREATE FULLTEXT INDEX user_title_ft ON myTable (title)";
        
		if(@mysqli_query($this->conn, $query);){
			echo "Full Text Index created successfully";
		}else{
			echo "Error creating Full Text Index: " . $conn->error;
			return FALSE;
		}
	}
    
	public function selectByTitle($title){ // 인덱스 컬럼인 title에서 $title포함하는 사용자 정보 조회
        $query = "SELECT * FROM myTable WHERE MATCH(title) AGAINST ('$title' IN NATURAL LANGUAGE MODE)";
		$result = @mysqli_query($this->conn, $query);
        
		return $result;
	}

	// 사용자 정보 저장 및 카테고리, 이미지 패스 저장 메소
	public function addMember($user_id, $title, $context, $thumbnail_path, $image_path, $category) {
		// mysqli_begin_transaction($this->conn); 해당 코드를 오토커밋 방식 대신 사용할 수도 있다.
		mysqli_autocommit($this->conn, FALSE);
		$query = "INSERT INTO `member` VALUES (NULL , '{$user_id}', '{$title}', '{$context}', NOW(), '{$thumbnail_path}')";
		
		$result = @mysqli_query($this->conn, $query);
		$id = get_insert_id();
		
		if ($result) {
			
			foreach($category as $value) { // 카테고리 저장 및 실패 시 롤백				
				$result = $this->addCategory($id, $value);
				if (!$result) {
					mysqli_rollback($this->conn);	
					return FALSE;
				}			
			}
			
			foreach($image_path as $path) { // 이미지 패스 저장 및 실패 시 롤백
				$result = $this->addImage($id, $path);
				if (!$result) {
					mysqli_rollback($this->conn);	
					return FALSE;
				}
			}			
			
			mysqli_commit($this->conn);	
			mysqli_autocommit($this->conn, TRUE);
			return TRUE;		
		}
		return FALSE;
	}	

	//카테고리 추가
	public function addCategory($user_id, $category_id) {
		$query = "INSERT INTO `member_categorys` VALUES (NULL, '{$user_id}', '{$category_id}')";
		$result = @mysqli_query($this->conn, $query);
		return $result;
	}	

	//이미지 추가
	public function addImage($user_id, $image_path) {
		$query = "INSERT INTO `member_images` VALUES (NULL, '{$user_id}', '{$image_path}')";
		$result = @mysqli_query($this->conn, $query);
		return $result;
	}
	
}

 

이런 방법을 통해 효율적인 FullText 인덱스 처리를 할 수 있습니다.