MongoDB
 sql >> Cơ Sở Dữ Liệu >  >> NoSQL >> MongoDB

Kết hợp toàn văn với chỉ mục khác

Trường hợp chính ở đây là kết quả tìm kiếm "văn bản" thường được ưu tiên hơn các điều kiện lọc khác trong truy vấn và do đó, điều cần thiết là "đầu tiên" lấy kết quả từ thành phần "văn bản", sau đó về cơ bản là "quét" cho các điều kiện khác trong tài liệu.

Loại tìm kiếm này có thể khó tối ưu hóa cùng với "phạm vi" hoặc bất kỳ loại điều kiện khớp "bất bình đẳng" nào trong liên kết với kết quả tìm kiếm văn bản và chủ yếu là do cách MongoDB xử lý loại chỉ mục "đặc biệt" này.

Để có một minh chứng ngắn, hãy xem xét thiết lập cơ bản sau:

db.texty.drop();

db.texty.insert([
    { "a": "a", "text": "something" },
    { "a": "b", "text": "something" },
    { "a": "b", "text": "nothing much" },
    { "a": "c", "text": "something" }
])

db.texty.createIndex({ "text": "text" })
db.texty.createIndex({ "a": 1 })

Vì vậy, nếu bạn muốn xem xét điều này với điều kiện tìm kiếm văn bản cũng như xem xét phạm vi trên trường khác ({ "$lt": "c" } ), thì bạn có thể xử lý như sau:

db.texty.find({ "a": { "$lt": "c" }, "$text": { "$search": "something" } }).explain()

Với đầu ra giải thích như (phần quan trọng):

           "winningPlan" : {
                    "stage" : "FETCH",
                    "filter" : {
                            "a" : {
                                    "$lt" : "c"
                            }
                    },
                    "inputStage" : {
                            "stage" : "TEXT",
                            "indexPrefix" : {

                            },
                            "indexName" : "text_text",
                            "parsedTextQuery" : {
                                    "terms" : [
                                            "someth"
                                    ],
                                    "negatedTerms" : [ ],
                                    "phrases" : [ ],
                                    "negatedPhrases" : [ ]
                            },
                            "inputStage" : {
                                    "stage" : "TEXT_MATCH",
                                    "inputStage" : {
                                            "stage" : "TEXT_OR",
                                            "inputStage" : {
                                                    "stage" : "IXSCAN",
                                                    "keyPattern" : {
                                                            "_fts" : "text",
                                                            "_ftsx" : 1
                                                    },
                                                    "indexName" : "text_text",
                                                    "isMultiKey" : true,
                                                    "isUnique" : false,
                                                    "isSparse" : false,
                                                    "isPartial" : false,
                                                    "indexVersion" : 1,
                                                    "direction" : "backward",
                                                    "indexBounds" : {

                                                    }
                                            }
                                    }
                            }
                    }
            },

Về cơ bản nói " đầu tiên lấy cho tôi kết quả văn bản và sau đó lọc những kết quả đó được tìm nạp theo điều kiện khác " . Vì vậy, rõ ràng chỉ có chỉ mục "văn bản" đang được sử dụng ở đây và sau đó tất cả các kết quả mà nó trả về sau đó sẽ được lọc bằng cách kiểm tra nội dung.

Điều này không tối ưu vì hai lý do, đó là có thể dữ liệu bị hạn chế tốt nhất bởi điều kiện "phạm vi" hơn là các kết quả phù hợp từ tìm kiếm văn bản. Thứ hai, mặc dù có một chỉ mục trên dữ liệu khác, nó không được sử dụng ở đây để so sánh. Vì vậy, toàn bộ tài liệu được tải cho mỗi kết quả và bộ lọc được kiểm tra.

Sau đó, bạn có thể xem xét định dạng chỉ mục "kết hợp" ở đây và ban đầu có vẻ hợp lý rằng nếu "phạm vi" cụ thể hơn cho lựa chọn, thì hãy bao gồm định dạng đó làm thứ tự tiền tố của các khóa được lập chỉ mục:

db.texty.dropIndexes();
db.texty.createIndex({ "a": 1, "text": "text" })

Nhưng có một vấn đề ở đây là khi bạn cố gắng chạy lại truy vấn:

db.texty.find({ "a": { "$lt": "c" }, "$text": { "$search": "something" } })

Nó sẽ dẫn đến lỗi:

Error:error:{"waitMS":NumberLong (0), "ok":0, "errmsg":"error xử lý truy vấn:ns =test.textyTree:$ và \ n a $ lt \" c \ "\ n TEXT:query =something, language =english, caseSensitive =0, diacriticSensitive =0, tag =NULL \ nSort:{} \ nProj:{} \ n planner đã trả về lỗi:không thể sử dụng chỉ mục văn bản để đáp ứng truy vấn $ text (nếu chỉ mục văn bản là ghép, các vị từ đẳng thức có được cung cấp cho tất cả các trường tiền tố không?) "," code ":2}

Vì vậy, mặc dù điều đó có vẻ "tối ưu", nhưng cách MongoDB xử lý truy vấn (và thực sự là lựa chọn chỉ mục) cho chỉ mục "văn bản" đặc biệt, thì việc "loại trừ" bên ngoài phạm vi này là không thể thực hiện được.

Tuy nhiên, bạn có thể thực hiện đối sánh "bình đẳng" về điều này theo cách rất hiệu quả:

db.texty.find({ "a": "b", "$text": { "$search": "something" } }).explain()

Với đầu ra giải thích:

           "winningPlan" : {
                    "stage" : "TEXT",
                    "indexPrefix" : {
                            "a" : "b"
                    },
                    "indexName" : "a_1_text_text",
                    "parsedTextQuery" : {
                            "terms" : [
                                    "someth"
                            ],
                            "negatedTerms" : [ ],
                            "phrases" : [ ],
                            "negatedPhrases" : [ ]
                    },
                    "inputStage" : {
                            "stage" : "TEXT_MATCH",
                            "inputStage" : {
                                    "stage" : "TEXT_OR",
                                    "inputStage" : {
                                            "stage" : "IXSCAN",
                                            "keyPattern" : {
                                                    "a" : 1,
                                                    "_fts" : "text",
                                                    "_ftsx" : 1
                                            },
                                            "indexName" : "a_1_text_text",
                                            "isMultiKey" : true,
                                            "isUnique" : false,
                                            "isSparse" : false,
                                            "isPartial" : false,
                                            "indexVersion" : 1,
                                            "direction" : "backward",
                                            "indexBounds" : {

                                            }
                                    }
                            }
                    }
            },

Vì vậy, chỉ mục được sử dụng và nó có thể được hiển thị để "lọc trước" nội dung được cung cấp cho đối sánh văn bản bằng đầu ra của điều kiện khác.

Tuy nhiên, nếu thực sự bạn giữ "tiền tố" cho chỉ mục làm (các) trường "văn bản" để tìm kiếm:

db.texty.dropIndexes();

db.texty.createIndex({ "text": "text", "a": 1 })

Sau đó thực hiện tìm kiếm:

db.texty.find({ "a": { "$lt": "c" }, "$text": { "$search": "something" } }).explain()

Sau đó, bạn thấy kết quả tương tự với kết quả khớp "bình đẳng" ở trên:

            "winningPlan" : {
                    "stage" : "TEXT",
                    "indexPrefix" : {

                    },
                    "indexName" : "text_text_a_1",
                    "parsedTextQuery" : {
                            "terms" : [
                                    "someth"
                            ],
                            "negatedTerms" : [ ],
                            "phrases" : [ ],
                            "negatedPhrases" : [ ]
                    },
                    "inputStage" : {
                            "stage" : "TEXT_MATCH",
                            "inputStage" : {
                                    "stage" : "TEXT_OR",
                                    "filter" : {
                                            "a" : {
                                                    "$lt" : "c"
                                            }
                                    },
                                    "inputStage" : {
                                            "stage" : "IXSCAN",
                                            "keyPattern" : {
                                                    "_fts" : "text",
                                                    "_ftsx" : 1,
                                                    "a" : 1
                                            },
                                            "indexName" : "text_text_a_1",
                                            "isMultiKey" : true,
                                            "isUnique" : false,
                                            "isSparse" : false,
                                            "isPartial" : false,
                                            "indexVersion" : 1,
                                            "direction" : "backward",
                                            "indexBounds" : {

                                            }
                                    }
                            }
                    }
            },

Sự khác biệt lớn ở đây so với lần thử đầu tiên là nơi filter được đặt trong chuỗi xử lý, cho biết rằng mặc dù không phải là đối sánh "tiền tố" (là tối ưu nhất), nội dung thực sự đang được quét khỏi chỉ mục "trước khi" được gửi đến giai đoạn "văn bản".

Vì vậy, nó được "lọc trước" nhưng tất nhiên không phải theo cách tối ưu nhất, và điều này là do bản chất của cách sử dụng chỉ mục "văn bản". Vì vậy, nếu bạn chỉ xem xét phạm vi đơn giản trên một chỉ mục của chính nó:

db.texty.createIndex({ "a": 1 })
db.texty.find({ "a": { "$lt": "c" } }).explain()

Sau đó, kết quả giải thích:

            "winningPlan" : {
                    "stage" : "FETCH",
                    "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                    "a" : 1
                            },
                            "indexName" : "a_1",
                            "isMultiKey" : false,
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 1,
                            "direction" : "forward",
                            "indexBounds" : {
                                    "a" : [
                                            "[\"\", \"c\")"
                                    ]
                            }
                    }
            },

Sau đó, ít nhất có indexBounds để xem xét và chỉ xem xét phần chỉ số nằm trong giới hạn đó.

Vì vậy, đó là sự khác biệt ở đây. Sử dụng cấu trúc "phức hợp" sẽ giúp bạn tiết kiệm một số chu kỳ lặp lại ở đây bằng cách có thể thu hẹp lựa chọn, nhưng nó vẫn phải quét tất cả các mục nhập chỉ mục để lọc và tất nhiên phải không là phần tử "tiền tố" trong chỉ mục trừ khi bạn có thể sử dụng đối sánh bình đẳng trên đó.

Không có cấu trúc phức hợp trong chỉ mục, bạn luôn trả về kết quả văn bản "đầu tiên", sau đó áp dụng bất kỳ điều kiện nào khác cho các kết quả đó. Ngoài ra, không thể "kết hợp / giao nhau" các kết quả khi xem chỉ mục "văn bản" và chỉ mục "bình thường" do xử lý công cụ truy vấn. Đó thường không phải là cách tiếp cận tối ưu, vì vậy việc lập kế hoạch để cân nhắc là rất quan trọng.

Nói tóm lại, lý tưởng nhất là kết hợp với "tiền tố" đối sánh "bình đẳng" và nếu không, hãy đưa vào chỉ mục "sau" định nghĩa văn bản.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. MongoDB:tìm và tìm thấy với tính năng lọc mảng lồng nhau

  2. Làm việc với các ký tự đặc biệt trong bộ sưu tập Mongo

  3. Đám mây lai so với đám mây công cộng đầy đủ - Ưu và nhược điểm

  4. Sự khác biệt giữa phương thức insert (), insertOne () và insertMany () là gì?

  5. Cách đặt mongod.conf bind_ip với nhiều địa chỉ ip