ค้นหาไฟล์ที่เรียงลำดับอย่างมีประสิทธิภาพ


12

ฉันมีไฟล์ขนาดใหญ่ที่มีหนึ่งสตริงในแต่ละบรรทัด ฉันต้องการทราบว่าสตริงอยู่ในไฟล์อย่างรวดเร็วหรือไม่ เป็นการดีที่จะทำได้โดยใช้อัลกอริทึมชนิดสับแบบไบนารี

Googling บางคนเปิดเผยlookคำสั่งด้วยการ-bตั้งค่าสถานะซึ่งสัญญาว่าจะค้นหาและส่งออกสตริงทั้งหมดที่เริ่มต้นด้วยคำนำหน้าที่กำหนดโดยใช้อัลกอริทึมการค้นหาแบบไบนารี โชคไม่ดีที่ดูเหมือนว่าจะทำงานไม่ถูกต้องและส่งคืนผลลัพธ์ที่เป็นโมฆะสำหรับสตริงที่ฉันรู้ว่าอยู่ในไฟล์ (พวกเขาถูกส่งคืนอย่างถูกต้องจากการgrepค้นหาที่เทียบเท่า)

ไม่มีใครรู้จักยูทิลิตี้หรือกลยุทธ์อื่นในการค้นหาไฟล์นี้อย่างมีประสิทธิภาพ


คำตอบยอดนิยมระบุการเรียงลำดับที่ไม่ถูกต้อง: ความจริงก็คือคุณต้องเรียงลำดับด้วย: LC_COLLATE = C sort -d สำหรับlookคำสั่งให้ทำงานอย่างถูกต้องเพราะดูเหมือนว่าจะไม่สนใจสถานที่และใช้ C เช่นการเรียงลำดับ hardcoded ฉันยังเปิดบั๊ก เนื่องจากพฤติกรรมที่สับสนนี้: bugzilla.kernel.org/show_bug.cgi?id=198011
Sur3

look -bFile too largeล้มเหลวสำหรับฉันกับข้อผิดพลาด ฉันคิดว่ามันกำลังพยายามอ่านเรื่องราวทั้งหมดในความทรงจำ
Brian Minton

คำตอบ:


9

มีความแตกต่างที่สำคัญระหว่างgrepและlook:

เว้นแต่จะระบุไว้เป็นอย่างอื่นอย่างชัดเจนgrepจะพบรูปแบบแม้กระทั่งบางแห่งในบรรทัด สำหรับlookสถานะ manpage:

look - แสดงบรรทัดที่ขึ้นต้นด้วยสตริงที่กำหนด

ฉันไม่ได้ใช้lookบ่อยนัก แต่มันก็ใช้ได้ดีกับตัวอย่างที่ฉันพยายาม


1
ไฟล์ที่ฉันต้องการค้นหามีประมาณ 110,000,000 บรรทัด ถ้าฉันทำegrep "^TEST" sortedlist.txt | wc -l ฉันจะได้ผลลัพธ์ 41,289 อย่างไรก็ตามlookคำสั่งที่เทียบเท่าlook -b TEST sortedlist.txt | wc -lให้ผลลัพธ์เพียง 1995 ผลลัพธ์ ฉันเกือบจะสงสัยว่ามีข้อบกพร่องlookหรือไม่
Matt

1
@Matt อาจlookจะใช้การตั้งค่าการเรียงหน้าแตกต่างจากโปรแกรมที่คุณใช้เรียงไฟล์
kasperd

4

อาจจะตอบช้าหน่อย:

Sgrep จะช่วยคุณ

Sgrep (grep เรียงลำดับ) ค้นหาไฟล์อินพุตที่เรียงลำดับสำหรับบรรทัดที่ตรงกับคีย์ค้นหาและส่งออกบรรทัดที่ตรงกัน เมื่อค้นหาไฟล์ขนาดใหญ่ sgrep จะเร็วกว่ายูนิกซ์ grep แบบดั้งเดิม แต่มีข้อ จำกัด ที่สำคัญ

  • ไฟล์อินพุตทั้งหมดต้องเรียงลำดับไฟล์ปกติ
  • คีย์การเรียงลำดับต้องเริ่มต้นที่จุดเริ่มต้นของบรรทัด
  • คีย์ค้นหาตรงเฉพาะที่จุดเริ่มต้นของบรรทัด
  • ไม่รองรับการแสดงออกปกติ

คุณสามารถดาวน์โหลดซอร์สได้ที่นี่: https://sourceforge.net/projects/sgrep/?source=typ_redirect

และเอกสารที่นี่: http://sgrep.sourceforge.net/

อีกวิธีหนึ่ง:

ฉันไม่ทราบว่าไฟล์มีขนาดใหญ่ขนาดไหนคุณควรลองแบบขนาน:

/programming/9066609/fastest-possible-grep

ฉันทำ grep กับไฟล์ที่มีขนาด> 100GB มันใช้งานได้ดี


2
นั่นไม่ใช่ในaskubuntu.com/a/701237/158442หรือไม่
muru

ใช่ฉันกรอกลิงค์ดาวน์โหลด ...
memorybox

หากเป็นเช่นนั้นคุณควรแก้ไขโพสต์นั้นแทนที่จะโพสต์คำตอบใหม่
muru

แนะนำให้โพสต์นั้น: sudo apt-get install sgrep เพื่อรับ sgrep, sgrep ในที่เก็บ buntu ไม่ใช่ sgrep นี้จริง ๆ , ฉันไม่แน่ใจว่ามันเป็นสิ่งเดียวกัน
memorybox

0

คุณสามารถแฮชไฟล์เป็นชิ้น ๆ แล้ว grep แค่ชิ้นที่คุณต้องการ:

for line in $(cat /usr/share/dict/american-english | tr '[:upper:]' '[:lower:]' | sort | uniq)
do
    prefix=$(echo $line | md5sum - | cut -c 1-2)
    mkdir -p $prefix
    echo $line | gzip >> $prefix/subwords
done

จากนั้นการค้นหาจะมีลักษณะดังนี้:

    prefix=$(echo $word | md5sum - | cut -c 1-2)
    zgrep -m 1 -w word $prefix/subwords

สิ่งนี้ทำสองสิ่ง:

  1. อ่านและเขียนไฟล์บีบอัด โดยทั่วไปจะเร็วกว่าที่จะวางโหลดบน cpu (เร็วมาก) แทนดิสก์ (ช้ามาก)
  2. สิ่งแฮชเพื่อให้ได้การกระจายที่เท่ากันโดยประมาณคุณสามารถใช้แฮชที่สั้นกว่าหรือยาวกว่าได้ตามที่คุณต้องการเพื่อลดขนาดของแต่ละชิ้น

0

sgrepอาจทำงานให้คุณได้:

sudo apt-get install sgrep
sgrep -l '"needle"' haystack.txt

หน้าโครงการhttp://sgrep.sourceforge.net/พูดว่า:

Sgrep ใช้อัลกอริธึมการค้นหาแบบไบนารีซึ่งเร็วมาก แต่ต้องใช้อินพุตที่เรียงลำดับ

สำหรับการแทรกอย่างไรก็ตามฉันคิดว่าไม่มีวิธีแก้ปัญหาที่ดีไปกว่าการใช้ฐานข้อมูล: /programming/10658380/shell-one-liner-to-add-a-line-to-a-sorted-file/ 33859372 # 33859372


3
sgrepในที่เก็บอูบุนตูเป็นจริงsgrep นี้ซึ่งถูกออกแบบมาเพื่อ "ค้นหาไฟล์สำหรับรูปแบบโครงสร้าง" และมีอะไรจะทำอย่างไรกับการค้นหาแบบทวิภาค
ingomueller.net

0

หากคุณต้องการมันเร็วมาก (O (1) เร็ว) คุณสามารถสร้างชุดแฮชเพื่อดู ฉันไม่สามารถหาการดำเนินการที่จะให้ฉันเก็บ pre-built ชุดกัญชาในแฟ้มและสอบสวนมันโดยไม่ต้องอ่านไฟล์ทั้งหมดลงในหน่วยความจำเพื่อรีดผมของตัวเอง

สร้างชุดแฮช ( -b/ --build):

./hashset.py --build string-list.txt strings.pyhashset

โพรบชุดแฮช ( -p/ --probe):

./hashset.py --probe strings.pyhashset \
    'Is this string in my string list?' 'What about this one?'

…หรือกับสตริงเพื่อค้นหาอินพุตมาตรฐาน:

printf '%s\n' 'Is this string in my string list?' 'What about this one?' |
./hashset.py --probe strings.pyhashset

คุณสามารถเงียบผลลัพธ์--probeด้วยตัวเลือก-q/ --quietถ้าคุณสนใจเฉพาะสถานะทางออก:

if ./hashset.py --quiet --probe strings.pyhashset ...; then
    echo 'Found'
else
    echo 'Not found'
fi

สำหรับตัวเลือกเพิ่มเติมดูคำอธิบายการใช้งานที่สามารถเข้าถึงได้ผ่านตัวเลือก-h/ --helpหรือREADMEไฟล์ที่แนบมา

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.