MySQL match () against ()-관련성 및 열별 정렬?


80

좋아, 그래서 여러 열에서 전체 텍스트 검색을 시도하고 있습니다. 다음과 같이 간단합니다.

SELECT * FROM pages WHERE MATCH(head, body) AGAINST('some words' IN BOOLEAN MODE)

이제 나는 다음과 같이 할 수 있었던 관련성에 따라 순서를 정하고 싶습니다. (몇 개의 단어가 발견 되었습니까?)

SELECT * , MATCH (head, body) AGAINST ('some words' IN BOOLEAN MODE) AS relevance 
FROM pages
WHERE MATCH (head, body) AGAINST ('some words' IN BOOLEAN MODE)
ORDER BY relevance

이제 제가 길을 잃은 부분이 head있습니다. 칼럼 의 관련성에 우선 순위를두고 싶습니다 .

나는 두 개의 관련성 열을 만들 수 있다고 생각합니다. 하나는에 대한 head것이고 하나는에 대한 것입니다 body. 그러나 그 시점에서 나는 표에서 다소 동일한 검색을 세 번 수행하고이 함수를 만드는 것에 대해 성능이 중요합니다. 쿼리는 조인되고 다른 테이블과 일치합니다.

내 주요 질문은 관련성을 검색하고 특정 열의 우선 순위를 지정하는 더 빠른 방법이 있습니까? (그리고 보너스로 단어가 열에 나오는 횟수만큼 관련성을 세울 수도 있습니까?)

어떤 제안이나 조언도 좋을 것입니다.

참고 : 나는 이것을 LAMP 서버에서 실행할 것입니다. (현지 테스트에서 WAMP)


SELECT 절 WHERE 절 모두에 MATCH ... AGAINST를 넣어야 합니까? SELECT 절에서 별칭을 지정하고 WHERE 절에서 별칭을 참조 할 수 없습니까? 나는 준비된 진술을 사용하려고하는데 이것은 나에게 중복되거나 이상하게 보입니다.
S. Imp

2
아니요, 5.5 이후의 MySQL 문서에서 언급했듯이 MATCH ... AGAINST는 SELECT 및 WHERE 모두에서 한 번 계산되므로 추가 오버 헤드가 없습니다.
Bob2u

답변:


156

이렇게 하면 원하는 머리 부분에 대한 관련성이 높아질 수 있습니다 . 두 배가되지는 않겠지 만, 아마도 당신을 위해 충분할 것입니다.

SELECT pages.*,
       MATCH (head, body) AGAINST ('some words') AS relevance,
       MATCH (head) AGAINST ('some words') AS title_relevance
FROM pages
WHERE MATCH (head, body) AGAINST ('some words')
ORDER BY title_relevance DESC, relevance DESC

-- alternatively:
ORDER BY title_relevance + relevance DESC

DB 엔진을 유연하게 전환 할 수있는 경우 조사 할 대안은 Postgres 입니다. 운영자의 가중치를 설정하고 순위를 가지고 놀 수 있습니다.


14
제쳐두고, MySQL 5.6은 InnoDB 테이블에서 전체 텍스트 검색을 지원합니다!
Jabari

1
이를 위해 SQL 바이올린을 제공 할 수 있습니까?
사용자

여러 검색이 얼마나 부정적인 영향을 미칩니 까? 4 개의 다른 가중치 요인이 있으므로 SELECT에서 4 개의 일치가 필요합니다. 그러면 성능이 훨씬 저하 될까요?
도베

@ToBe 나는 MATCHMySQL이 내부적으로 작동하는 방식으로 인해 여러 명령문 을 사용하는 데 추가 오버 헤드가 없다고 한 사람 이상이 다른 유사한 질문에서 보았습니다 .
BadHorsie 2016-06-08

이 두 가지를 실행하십시오. ALTER TABLE talk_webpages ADD FULLTEXT(head)ALTER TABLE talk_webpages ADD FULLTEXT(head, body)
Supun Kavinda

15

필요한 사람을 위해 추가하기 만하면됩니다. 테이블을 변경하는 것을 잊지 마십시오!

ALTER TABLE table_name ADD FULLTEXT(column_name);

3
위의 명령을 두 번 이상 실행하면 동일한 열에 대해 여러 인덱스가 생성됩니다. 따라서이 명령을 한 번만 실행하십시오.
hakiko

더 좋은 방법은 tablename (column_name (s))에 CREATE FULLTEXT INDEX indexname을 사용하는 것입니다. 또한 인덱스를 생성하기 전에 실제로 인덱스가 존재하는지 확인해야합니다. 다음을 사용하여 존재하는지 확인할 수 있습니다. SELECT INDEX_NAME FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_CATALOG= ' def'AND TABLE_SCHEMA= DATABASE () AND TABLE_NAME= 'tablename'AND INDEX_NAME= 'indexname';
Dave Hilditch

9

나는 그렇게 한 적이 없지만

MATCH (head, head, body) AGAINST ('some words' IN BOOLEAN MODE)

머리에서 찾은 성냥에 두 배의 가중치를 부여 해야 합니다.


문서 페이지 에서이 주석을 읽으십시오 . 귀하에게 가치가있을 것이라고 생각했습니다.

게시자 : Patrick O'Lone, 2002 년 12 월 9 일 오전 6:51

문서에서 IN BOOLEAN MODE는 거의 항상 1.0의 관련성을 반환한다는 점에 유의해야합니다. 의미있는 관련성을 얻으려면 다음을 수행해야합니다.

SELECT MATCH('Content') AGAINST ('keyword1 keyword2') as Relevance 
FROM table 
WHERE MATCH ('Content') AGAINST('+keyword1+keyword2' IN BOOLEAN MODE) 
HAVING Relevance > 0.2 
ORDER BY Relevance DESC 

BOOLEAN MODE를 사용하는 WHERE 절과 결합 된 관련성 요소를 얻기 위해 일반 관련성 쿼리를 수행하고 있습니다. BOOLEAN MODE는 BOOLEAN 검색의 요구 사항을 충족하는 하위 집합을 제공하고, 관련성 쿼리는 관련성 요소를 충족하며, HAVING 절 (이 경우)은 문서가 검색과 관련이 있는지 확인합니다 (예 : 점수가 0.2 미만인 문서). 관련이없는 것으로 간주 됨). 이를 통해 관련성별로 주문할 수도 있습니다.

이것은 IN BOOLEAN MODE가 작동하는 방식의 버그 일 수도 있고 아닐 수도 있지만, 메일 링리스트에서 읽은 댓글은 IN BOOLEAN MODE의 관련성 순위가 그리 복잡하지 않아 실제로 관련 문서를 제공하기에는 부족하다는 것을 암시합니다. BTW-두 개의 MATCH 절이 다르더라도 MySQL이 FULLTEXT 검색을 한 번만 수행하는 것처럼 보이기 때문에이 작업에 대한 성능 손실을 알아 차리지 못했습니다. 이를 증명하려면 EXPLAIN을 사용하십시오.

따라서 "이를 증명하려면 EXPLAIN을 사용"해야하지만 전체 텍스트 검색을 두 번 호출하는 것에 대해 걱정할 필요가없는 것 같습니다.


1
안타깝게도 match () 함수에 머리를 두 번 추가하면 작동하지 않습니다. 쿼리가 단어가 발생한 횟수를 계산하지 않기 때문일까요? 참조하신 페이지도 사용하고 있지만 어떤 이유로 든 작동하지 않을 수 있습니다. 아직 열을 색인화하지 않았기 때문에 "IN BOOLEAN MODE"태그 없이는 검색 할 수 없습니다. .
Kristoffer la Cour 2011-06-07

booleen이 아닌 검색은 발생 횟수를 반환한다고 생각하지만 booleen은 그렇지 않습니까?
jisaacstone 2011-06-07

내일 더 자세히 살펴 보 겠지만 지금은 잠시 기다려 보겠습니다. 답변 해 주셔서 감사합니다.이 문제를 파악하면 도움이되는지 알아 보겠습니다.
Kristoffer la Cour 2011-06-07

IN BOOLEAN MODE를 사용하는 데 문제가 있었고 관련성별로 주문했는데 관련성이 항상 1로 반환되는 문제가 해결되었습니다. 감사합니다.
Jazzy

점수 필드를 생성하면 내 문제가 해결되었습니다. 결과를 얻었지만 많은 부분이 완전한 소음이었습니다. 감사합니다, +1
크리스 베이커

4

나도 이걸 가지고 놀고 있었어. 무게를 추가 할 수있는 한 가지 방법은 코드의 ORDER BY 영역에 있습니다.

예를 들어 3 개의 서로 다른 열을 일치시키고 특정 열에 더 많은 가중치를 부여하려는 경우 :

SELECT search.*,
MATCH (name) AGAINST ('black' IN BOOLEAN MODE) AS name_match,
MATCH (keywords) AGAINST ('black' IN BOOLEAN MODE) AS keyword_match,
MATCH (description) AGAINST ('black' IN BOOLEAN MODE) AS description_match
FROM search
WHERE MATCH (name, keywords, description) AGAINST ('black' IN BOOLEAN MODE)
ORDER BY (name_match * 3  + keyword_match * 2  + description_match) DESC LIMIT 0,100;

이것은 정말로 무거운 쿼리가 아닌가?
Beanow

5
수학을 select 문으로 옮기면 부하가 많이 줄어 듭니다. SELECT search.*, (MATCH (name) AGAINST ('black' IN BOOLEAN MODE) * 3) + (MATCH (keywords) AGAINST ('black' IN BOOLEAN MODE)*2 + MATCH (description) AGAINST ('black' IN BOOLEAN MODE)) AS totalScore , FROM search WHERE MATCH (name, keywords, description) AGAINST ('black' IN BOOLEAN MODE) ORDER BY totalScore DESC LIMIT 0,100;
invertedSpear
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.