2016-10-25 8 views
2

Мне нужно объединить XML-файлы с различной структурой, используя PHP. Я делаю это;Объединить XML-файлы на основе сходства записей

  1. Прочитайте первый файл XML с помощью simplexml_load_file()
  2. переформатировать элементы с использованием новой структуры с помощью SimpleXMLElement() класса
  3. Сделайте то же самое для другого файла, увеличивающимся первый SimpleXMLElement() экземпляр
  4. Сохранить вновь объединенный файл XML ,

Пока все хорошо. Сложная часть: первый файл имеет ок. 3000 записей, а второй файл - 5000. Почти 2000 из этих записей на самом деле одинаковы; просто, может быть, несколько букв отличаются. Как например; «Lenovo G50-70 CoreI5», а другой может быть «Lenovo G5070 I5».

Вопрос в том, как я могу сопоставить запись первого файла с равной записью второго файла; так что на самом деле это всего лишь одна запись в целом, в новом объединенном файле?

Я использую функцию similar_text() функции PHP и SmithWatermanGotoh, чтобы рассчитать подобие, и это соответствует значению 86%; которого достаточно для меня. Но повторить все записи другого файла, чтобы соответствовать только одной записи, приходит совершенно неразумно и ресурс, потребляющий меня. Beucase означает ок. 7 Мбайт загруженного в память файла занимает минимум 15 000 итераций каждый раз, когда я сохраняю новый обновленный файл.

Я считаю, что нужно вставить все записи в таблицу базы данных и использовать Sphinx Search для сопоставления записей; но я не уверен, действительно ли это помогает.

+1

Если проблема с памятью, могут помочь [генераторы] (http://php.net/manual/ro/language.generators.overview.php). – Andrew

+1

Я думаю, что главная проблема здесь заключается в сложности 'similar_text()'. Если бы я был вами, я определяю набор правил для форматирования каждой записи уникальным способом, тогда вы можете легко найти дубликаты. –

+1

@CasimiretHippolyte, я не мог практиковать ваше предложение четко, не так ли, пожалуйста? Кстати, есть те же самые записи, что и дубликаты; но есть также записи, которые на деле совпадают, но не точные дубликаты. Как и данный пример в вопросе. – Turab

ответ

1

Лучший подход, который я мог видеть, - использование пользовательского обратного вызова с помощью функции array_uintersect(). Этот способ работает в таких шагах, как;

1- Напишите функцию сравнения, которая рассчитает сходство. Проверьте руководство array_uintersect() от php.net, чтобы иметь представление о том, как вам нужно написать эту функцию обратного вызова. Скажем, это имя будет find_similar_entries()

2 Соберите обе записи из разных XML-файлов в два массива. (Для быстрого пути сделайте сначала json_encode(), а затем json_decode() назад.)

3- Функция пересечения найти аналогичные записи; $similar_products = array_uintersect($xml_array1, $xml_array2, 'find_similar_entries');

4 Теперь у вас есть аналогичные записи, собранные в одном массиве.

5. Вызовите array_diff(), чтобы удалить аналогичные записи из исходных массивов.

6- Наконец, объедините все три массива в новую структуру XML по вашему желанию, используя класс SimpleXMLElement().

Note1: Я использовал similar_text() и SmithWatermanGotoh для расчета сходства, и они хорошо работают вместе, что я могу сказать. Но когда дело доходит до очень близких названий продуктов, которые могут отличаться лишь несколькими символами друг от друга, они будут «идентичны». Вы ничего не можете с этим поделать, кроме выделения отличительных слов из строк. Как «имя модели» в моем случае.

Примечание2: Этот метод работает так, как ожидалось, но функции пересечения PHP имеют ошибку, которая, как мне кажется, делает эту функцию настолько медленной. Для этого я создал a bug report. Пересечение сравнивает не только элементы двух массивов только с перекрестными; но он также сравнивает собственные элементы массива. Это на самом деле нелогично, потому что пересечение может быть рассчитано только путем сравнения как минимум двух сторон. Поэтому сравнение одного массива изнутри не является фактически «пересечением». Вот почему, если у вас большие файлы, ваш скрипт умрет, если вы просто запустите это прямо. Может быть, вы можете сделать это куском куска.