Существует множество сервисов по подбору синонимов, но они редко справляются с терминами, которые содержат в себе более одного слова. Для подбора синонимов для более сложных выражений могут помочь Викиданные.
Мало кто знает, что помимо стандартной Википедии существует дополнительная база данных Викиданные(Wikidata), которая представляет собой граф знаний фонда Викимедия. Сейчас она интегрирована в саму Википедию, поэтому для многих статей в левом меню можно найти пункт Элемент Викиданных. Викиданные представлены в модели RDF, то есть информация имеет вид триплетов, которые характеризуют сущность. Триплет выглядит, как утверждение субьект - предикат - обьект. Пример, для сущности Англия одним из таких информационных триплетов представлен: Англия - имеет столицу - Лондон.
Один из предикатов(типов связи) это altLabel, подразумевающий под собой альтернативные названия, который как раз таки и поможет нам в поиске синонимов.
Сразу стоит учитывать, что Викиданные это очень обширная база знаний, но, тем не менее, не совершенная. Поэтому, для терминов, которые там не представлены, или представлены, но для их сущностей нет введенных альтернативных названий, синонимов найдено не будет.
Поиск элемента в базе знаний
В первую очередь нужно найти сущность викиданных, представляющую данный термин. Для этого нужно найти его уникальный идентификатор(Q_id). Это можно сделать послав запрос через Wikidata API.
Полную документацию на API можно найти на https://www.mediawiki.org/wiki/API:Main_page
import requests
session = requests.Session()
URL = 'https://www.wikidata.org/w/api.php'
def wbgetentities(name):
res = session.post(URL, data={
'action': 'wbsearchentities',
'search': name,
'language':'ru',
'format': 'json',
})
try:
res_json = res.json()['search'][0]['id']
except:
res_json = None
return res_json
Q_id = wbgetentities(term)
Поиск синонимов
Для поиска синонима используем SPARQL. SPARQL это язык запросов к данным RDF, который позволяет быстро искать данные по запросу. Он позволит нам выполнить поиск альтернативных названий для нашей сущности по предикату altLabel.
Для отправки запросов sparql была использована библиотека sparql-client.
import sparql
def create_query(first_id):
q = ('''
PREFIX entity: <http://www.wikidata.org/entity/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
SELECT ?syno
WHERE {
?O ?P ?id .
OPTIONAL{?id skos:altLabel ?syno
filter (lang(?syno) = 'ru')}
VALUES ?id {entity:'''+ first_id +'''}
SERVICE wikibase:label {bd:serviceParam wikibase:language "ru" .}}''')
return q
synonyms = []
query = create_query(Q_id)
result = sparql.query('https://query.wikidata.org/sparql', query)
for r in result:
values = sparql.unpack_row(r)
if values[0] not in synonyms:
synonyms.append(values[0])
print(synonyms)
Таким образом, код выдаст список синонимов для термина, если они есть в системе Викиданных. Так же можно найти синонимы на другом языке, если поменять в запросе код ‘ru’ на код другого языка, представленного в списке https://www.wikidata.org/wiki/Help:Wikimedia_language_codes/lists/all