Лучший способ решить эту проблему — немного изменить структуру данных, так как полнотекстовые индексы могут работать только с одним атрибутом, а двойной запрос индекса ни в коем случае не будет быстрым. Поэтому мы используем анонимный граф, чтобы связать строки с их объектом.
Итак, мы создаем две (вершинные) коллекции, одну коллекцию ребер, одну коллекцию вершин с полнотекстовым индексом:
db._create("dishStrings")
db._createEdgeCollection("dishEdges")
db._create("dish")
db.dishStrings.ensureIndex({type: "fulltext", fields: [ "name" ]});
И сохраните к ним документы со связывающими их отношениями. Мы используем атрибут _key
, который используется для ссылки на вершины в отношениях ребер _from
и _to
:
db.dishStrings.save({"_key": "1001", "name": "Regular" , type: "Batter"});
db.dishStrings.save({"_key": "1002", "name": "Chocolate", type: "Batter" });
db.dishStrings.save({"_key": "1003", "name": "Blueberry", type: "Batter"});
db.dishStrings.save({"_key": "1004", "name": "Devil's Food", type: "Batter"});
db.dishStrings.save({"_key": "5001", "name": "None", type: "Topping"});
db.dishStrings.save({"_key": "5002", "name": "Glazed", type: "Topping"});
db.dishStrings.save({"_key": "5005", "name": "Sugar", type: "Topping"});
db.dishStrings.save({"_key": "5007", "name": "Powdered Sugar", type: "Topping"});
db.dishStrings.save({"_key": "5006", "name": "Chocolate with Sprinkles", type: "Topping"});
db.dishStrings.save({"_key": "5003", "name": "Chocolate", type: "Topping"});
db.dishStrings.save({"_key": "5004", "name": "Maple", type: "Topping"});
db.dishEdges.save("dishStrings/1001", "dish/batter", {tasty: true, type: "Batter"})
db.dishEdges.save("dishStrings/1002", "dish/batter", {tasty: true, type: "Batter"})
db.dishEdges.save("dishStrings/1003", "dish/batter", {tasty: true, type: "Batter"})
db.dishEdges.save("dishStrings/1004", "dish/batter", {tasty: true, type: "Batter"})
db.dishEdges.save("dishStrings/5001", "dish/batter", {tasty: true, type: "Topping"})
db.dishEdges.save("dishStrings/5002", "dish/batter", {tasty: true, type: "Topping"})
db.dishEdges.save("dishStrings/5003", "dish/batter", {tasty: true, type: "Topping"})
db.dishEdges.save("dishStrings/5004", "dish/batter", {tasty: true, type: "Topping"})
db.dishEdges.save("dishStrings/5005", "dish/batter", {tasty: true, type: "Topping"})
db.dishEdges.save("dishStrings/5006", "dish/batter", {tasty: true, type: "Topping"})
db.dishEdges.save("dishStrings/5007", "dish/batter", {tasty: true, type: "Topping"})
db.dish.save({_key: "batter", tasty: true})
Мы подтверждаем, что полнотекстовый индекс будет работать:
db._query("FOR oneDishStr IN FULLTEXT(dishStrings, 'name', 'Chocolate')" +
" RETURN oneDishStr").toArray()
( .toArray()
выведет нам результат на консоль) Получаем 3 попадания, одно тесто, две начинки. Поскольку строки поиска могут содержать непроверенные строки, мы скорее используем переменные связывания, чтобы обойти инъекции:
db._query("FOR oneDishStr IN FULLTEXT(dishStrings, 'name', @searchString) " +
" RETURN oneDishStr",
{searchString: "Chocolate"});
Теперь давайте воспользуемся краевым отношением, чтобы найти подключенную тарелку:
db._query("FOR oneDishStr IN FULLTEXT(dishStrings, 'name', @searchString) "+
"RETURN {str: oneDishStr, " +
"dishes: NEIGHBORS(dishStrings, dishEdges, oneDishStr," +
" 'outbound')}",
{searchString: "Chocolate"})
Это был старый (до версии 2.7) способ использования графиков, так как мы хотим использовать быстрые фильтры, давайте переведем это в новый синтаксис 2.8:
db._query("FOR oneDishStr IN FULLTEXT(dishStrings, 'name', @searchString) " +
" FOR v IN 1..1 OUTBOUND oneDishStr dishEdges RETURN " +
" {str: oneDishStr, dish: v}",
{searchString: "Chocolate"})
Мы видим, что в обоих случаях мы получаем один обход для каждого из 3 результатов полнотекстового поиска для Chocolate
. Теперь нас интересуют только попадания Toppings
, поэтому мы будем фильтровать все ребра, которые не относятся к типу Topping
:
db._query("FOR oneDishStr IN FULLTEXT(dishStrings, 'name', @searchString) "+
" FOR v, e IN 1..1 OUTBOUND oneDishStr dishEdges " +
" FILTER e.type == 'Topping' " +
" RETURN {str: oneDishStr, dish: v}",
{searchString: "Chocolate"})
person
dothebart
schedule
15.01.2016