Розбір рядка адреси (вулиця [будинок]) засобами Golang і Postgis

    Hi,% habrauser%.
Зіткнувся я днями з цікавим завданням — користувач вводить рядок, яка може бути вулицею з будинком, просто вулицею або взагалі не вулицею, а нам треба дізнатися чи мав він на увазі вулицю з будинком і відповідне йому підказати.
 
— Здавалося б чого простіше — розбий рядок по пробілу і насолоджуйся — подумав Штірліц
 - А як щодо вулиці Павла Корчагіна — шепнула птах Обломінго
 - Ем, ну номер будинку же напевно число — сказав Штірліц
 - Ага, корп1 — хороше число
 - Мдя, доведеться винаходити велосипед
 
 
 

І розчохлив Штіріц плюсомет Golang, да зарядив у нього Postgis…

І так, що ми маємо — пристрій випадкового введення користувача, якусь рядок і гостру необхідність виконати певну дію в залежності від того, чи є те, що ввів користувач вулицею з будинком
  
 
const MARK_STEP = 20
func AnalyzeString(str string) (result int, street, house string) {
	result = 100
	LastSpace := strings.LastIndex(str, " ")
	if LastSpace < 1 {
		result = 0
		street = str
		return result, street, house
	}
	if LastSpace < (len([]rune(str)) - 6) {
		result -= MARK_STEP
	} else {
		result += MARK_STEP
	}
	street = str[:LastSpace]
	house = str[LastSpace+1:]
	if models.StreetCount(street) > 0 {
		result += MARK_STEP * 2 
	} else {
		result -= MARK_STEP * 2 
	}
	if models.StreetCount(str) > 0 {
		result -= MARK_STEP
	} else {
		result += MARK_STEP
	}
	if models.HouseCount(street, house) > 0 {
		result += MARK_STEP 
	} else {
		result -= MARK_STEP * 4 
	}
	var int_count, char_count uint8
	for _, run := range []rune(house) {
		if (run > 47) && (run < 58) {
			int_count++
		} else {
			char_count++
		}
	}
	switch {
	case char_count == 0:
		{
			result += MARK_STEP * 3
		}
	case int_count == 0:
		{
			result -= MARK_STEP * 4
		}
	case int_count == char_count:
		{
			result += MARK_STEP
		}
	case int_count > char_count:
		{
			result += MARK_STEP * 2
		}
	case char_count > int_count:
		{
			result -= MARK_STEP
		}
	}
	return result, street, house
}

 
І так, що ж це за функція і що вона робить?
Функція приймає на вхід рядок введену користувачем і аналізує її повертаючи ймовірність того, що це вулиця з будинком, окремо вулицю і окремо будинок.
Якщо ймовірність більше 200 — можете не сумніватися — користувач мав на увазі вулицю з будинком.
 
Ймовірно ви помітили виклики StreetCount (street) і HouseCount (street, house)
в принципі за ними криється два банальний SQL запиту
 
 
rows, err := DB.Query("SELECT COUNT(*) FROM planet_osm_line WHERE highway <> '' AND name ILIKE $1 ", "%"+name+"%")

і
 
rows, err := DB.Query("SELECT COUNT(house.*) FROM planet_osm_polygon AS house WHERE \"addr:street\" ILIKE $1 AND \"addr:housenumber\" ILIKE $2", "%"+streetName+"%", "%"+houseNum+"%")

відповідно
 
І так, тепер по порядку
Стартова ймовірність 100, розбиваємо рядок за останнім прогалині, якщо не вийшло (немає пробілу) — то до біса все це не вулиця з будинком.
Якщо ж вийшло, то дивимося скільки символів залишилося після пробілу, якщо менше 6 (це число, як і багато інших підібрані за методом професора тикати Неба Пальця), то варто збільшити ймовірність, а якщо більше або дорівнює, то зменшити.
 
Вже якось змінивши ймовірність, або взагалі вийшовши з функції плакатися до гарбаж колектору, продовжуємо нашу епопею (ну або продовжуємо, дядько Гарбажа не любить відпускати).
Все, що до останнього пробілу вважаємо вулицею, а те, що після — будинком.
Далі просимо Postgis подивитися, скільки вулиць схоже на те, що ввів наш користувач, якщо такі взагалі є, то підвищуємо ймовірність, якщо ні, то зменшуємо (ні, не виходимо, адже цілком можливо, що вулиці ще немає в базі).
Тепер спробуємо пошукати в базі вулиці по заданій стрічці, якщо є, то варто притримати коней і знизити ймовірність, а якщо ні, то позалицятися галопом.
Повторимо ту-ж саму операцію з будинками, запитай Postgis про те, чи є вдома з схожим номером, що стоять на схожих вулицях.
 
Ну все, більше база нам не знадобитися.
Тепер розкладемо рядок на символи і порахуємо скільки у нас є цифр, а скільки літер та інших символів, думаю відповідну конструкцію switch — case пояснювати не треба.
 
Ось таким от не хитрим макаром Штірліц виконав чергове завдання ставки, поборов птицю Обломінго, врятував дракона від принцеси, підміняючи марио
Усім спасибі, всі вільні, а я, Штірліц, піду почитаю далі Хабре.
    
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.